162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * n_tty.c --- implements the N_TTY line discipline.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This code used to be in tty_io.c, but things are getting hairy
662306a36Sopenharmony_ci * enough that it made sense to split things off.  (The N_TTY
762306a36Sopenharmony_ci * processing has changed so much that it's hardly recognizable,
862306a36Sopenharmony_ci * anyway...)
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Note that the open routine for N_TTY is guaranteed never to return
1162306a36Sopenharmony_ci * an error.  This is because Linux will fall back to setting a line
1262306a36Sopenharmony_ci * to N_TTY if it can not switch to any other line discipline.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Written by Theodore Ts'o, Copyright 1994.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * This file also contains code originally written by Linus Torvalds,
1762306a36Sopenharmony_ci * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Reduced memory usage for older ARM systems  - Russell King.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
2262306a36Sopenharmony_ci *		the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
2362306a36Sopenharmony_ci *		who actually finally proved there really was a race.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
2662306a36Sopenharmony_ci *		waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
2762306a36Sopenharmony_ci *		Also fixed a bug in BLOCKING mode where n_tty_write returns
2862306a36Sopenharmony_ci *		EAGAIN
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <linux/bitmap.h>
3262306a36Sopenharmony_ci#include <linux/bitops.h>
3362306a36Sopenharmony_ci#include <linux/ctype.h>
3462306a36Sopenharmony_ci#include <linux/errno.h>
3562306a36Sopenharmony_ci#include <linux/export.h>
3662306a36Sopenharmony_ci#include <linux/fcntl.h>
3762306a36Sopenharmony_ci#include <linux/file.h>
3862306a36Sopenharmony_ci#include <linux/jiffies.h>
3962306a36Sopenharmony_ci#include <linux/math.h>
4062306a36Sopenharmony_ci#include <linux/poll.h>
4162306a36Sopenharmony_ci#include <linux/ratelimit.h>
4262306a36Sopenharmony_ci#include <linux/sched.h>
4362306a36Sopenharmony_ci#include <linux/signal.h>
4462306a36Sopenharmony_ci#include <linux/slab.h>
4562306a36Sopenharmony_ci#include <linux/string.h>
4662306a36Sopenharmony_ci#include <linux/tty.h>
4762306a36Sopenharmony_ci#include <linux/types.h>
4862306a36Sopenharmony_ci#include <linux/uaccess.h>
4962306a36Sopenharmony_ci#include <linux/vmalloc.h>
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#include "tty.h"
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/*
5462306a36Sopenharmony_ci * Until this number of characters is queued in the xmit buffer, select will
5562306a36Sopenharmony_ci * return "we have room for writes".
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_ci#define WAKEUP_CHARS 256
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * This defines the low- and high-watermarks for throttling and
6162306a36Sopenharmony_ci * unthrottling the TTY driver.  These watermarks are used for
6262306a36Sopenharmony_ci * controlling the space in the read buffer.
6362306a36Sopenharmony_ci */
6462306a36Sopenharmony_ci#define TTY_THRESHOLD_THROTTLE		128 /* now based on remaining room */
6562306a36Sopenharmony_ci#define TTY_THRESHOLD_UNTHROTTLE	128
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/*
6862306a36Sopenharmony_ci * Special byte codes used in the echo buffer to represent operations
6962306a36Sopenharmony_ci * or special handling of characters.  Bytes in the echo buffer that
7062306a36Sopenharmony_ci * are not part of such special blocks are treated as normal character
7162306a36Sopenharmony_ci * codes.
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_ci#define ECHO_OP_START 0xff
7462306a36Sopenharmony_ci#define ECHO_OP_MOVE_BACK_COL 0x80
7562306a36Sopenharmony_ci#define ECHO_OP_SET_CANON_COL 0x81
7662306a36Sopenharmony_ci#define ECHO_OP_ERASE_TAB 0x82
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define ECHO_COMMIT_WATERMARK	256
7962306a36Sopenharmony_ci#define ECHO_BLOCK		256
8062306a36Sopenharmony_ci#define ECHO_DISCARD_WATERMARK	N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#undef N_TTY_TRACE
8462306a36Sopenharmony_ci#ifdef N_TTY_TRACE
8562306a36Sopenharmony_ci# define n_tty_trace(f, args...)	trace_printk(f, ##args)
8662306a36Sopenharmony_ci#else
8762306a36Sopenharmony_ci# define n_tty_trace(f, args...)	no_printk(f, ##args)
8862306a36Sopenharmony_ci#endif
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistruct n_tty_data {
9162306a36Sopenharmony_ci	/* producer-published */
9262306a36Sopenharmony_ci	size_t read_head;
9362306a36Sopenharmony_ci	size_t commit_head;
9462306a36Sopenharmony_ci	size_t canon_head;
9562306a36Sopenharmony_ci	size_t echo_head;
9662306a36Sopenharmony_ci	size_t echo_commit;
9762306a36Sopenharmony_ci	size_t echo_mark;
9862306a36Sopenharmony_ci	DECLARE_BITMAP(char_map, 256);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/* private to n_tty_receive_overrun (single-threaded) */
10162306a36Sopenharmony_ci	unsigned long overrun_time;
10262306a36Sopenharmony_ci	unsigned int num_overrun;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* non-atomic */
10562306a36Sopenharmony_ci	bool no_room;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* must hold exclusive termios_rwsem to reset these */
10862306a36Sopenharmony_ci	unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
10962306a36Sopenharmony_ci	unsigned char push:1;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* shared by producer and consumer */
11262306a36Sopenharmony_ci	u8 read_buf[N_TTY_BUF_SIZE];
11362306a36Sopenharmony_ci	DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
11462306a36Sopenharmony_ci	u8 echo_buf[N_TTY_BUF_SIZE];
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* consumer-published */
11762306a36Sopenharmony_ci	size_t read_tail;
11862306a36Sopenharmony_ci	size_t line_start;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* # of chars looked ahead (to find software flow control chars) */
12162306a36Sopenharmony_ci	size_t lookahead_count;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* protected by output lock */
12462306a36Sopenharmony_ci	unsigned int column;
12562306a36Sopenharmony_ci	unsigned int canon_column;
12662306a36Sopenharmony_ci	size_t echo_tail;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	struct mutex atomic_read_lock;
12962306a36Sopenharmony_ci	struct mutex output_lock;
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1))
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic inline size_t read_cnt(struct n_tty_data *ldata)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	return ldata->read_head - ldata->read_tail;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic inline u8 read_buf(struct n_tty_data *ldata, size_t i)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	return ldata->read_buf[MASK(i)];
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic inline u8 *read_buf_addr(struct n_tty_data *ldata, size_t i)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	return &ldata->read_buf[MASK(i)];
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic inline u8 echo_buf(struct n_tty_data *ldata, size_t i)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	smp_rmb(); /* Matches smp_wmb() in add_echo_byte(). */
15262306a36Sopenharmony_ci	return ldata->echo_buf[MASK(i)];
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic inline u8 *echo_buf_addr(struct n_tty_data *ldata, size_t i)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	return &ldata->echo_buf[MASK(i)];
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/* If we are not echoing the data, perhaps this is a secret so erase it */
16162306a36Sopenharmony_cistatic void zero_buffer(const struct tty_struct *tty, u8 *buffer, size_t size)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	if (L_ICANON(tty) && !L_ECHO(tty))
16462306a36Sopenharmony_ci		memset(buffer, 0, size);
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic void tty_copy(const struct tty_struct *tty, void *to, size_t tail,
16862306a36Sopenharmony_ci		     size_t n)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
17162306a36Sopenharmony_ci	size_t size = N_TTY_BUF_SIZE - tail;
17262306a36Sopenharmony_ci	void *from = read_buf_addr(ldata, tail);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (n > size) {
17562306a36Sopenharmony_ci		tty_audit_add_data(tty, from, size);
17662306a36Sopenharmony_ci		memcpy(to, from, size);
17762306a36Sopenharmony_ci		zero_buffer(tty, from, size);
17862306a36Sopenharmony_ci		to += size;
17962306a36Sopenharmony_ci		n -= size;
18062306a36Sopenharmony_ci		from = ldata->read_buf;
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	tty_audit_add_data(tty, from, n);
18462306a36Sopenharmony_ci	memcpy(to, from, n);
18562306a36Sopenharmony_ci	zero_buffer(tty, from, n);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/**
18962306a36Sopenharmony_ci * n_tty_kick_worker - start input worker (if required)
19062306a36Sopenharmony_ci * @tty: terminal
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci * Re-schedules the flip buffer work if it may have stopped.
19362306a36Sopenharmony_ci *
19462306a36Sopenharmony_ci * Locking:
19562306a36Sopenharmony_ci *  * Caller holds exclusive %termios_rwsem, or
19662306a36Sopenharmony_ci *  * n_tty_read()/consumer path:
19762306a36Sopenharmony_ci *	holds non-exclusive %termios_rwsem
19862306a36Sopenharmony_ci */
19962306a36Sopenharmony_cistatic void n_tty_kick_worker(const struct tty_struct *tty)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	/* Did the input worker stop? Restart it */
20462306a36Sopenharmony_ci	if (unlikely(READ_ONCE(ldata->no_room))) {
20562306a36Sopenharmony_ci		WRITE_ONCE(ldata->no_room, 0);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		WARN_RATELIMIT(tty->port->itty == NULL,
20862306a36Sopenharmony_ci				"scheduling with invalid itty\n");
20962306a36Sopenharmony_ci		/* see if ldisc has been killed - if so, this means that
21062306a36Sopenharmony_ci		 * even though the ldisc has been halted and ->buf.work
21162306a36Sopenharmony_ci		 * cancelled, ->buf.work is about to be rescheduled
21262306a36Sopenharmony_ci		 */
21362306a36Sopenharmony_ci		WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
21462306a36Sopenharmony_ci			       "scheduling buffer work for halted ldisc\n");
21562306a36Sopenharmony_ci		tty_buffer_restart_work(tty->port);
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic ssize_t chars_in_buffer(const struct tty_struct *tty)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	const struct n_tty_data *ldata = tty->disc_data;
22262306a36Sopenharmony_ci	size_t head = ldata->icanon ? ldata->canon_head : ldata->commit_head;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	return head - ldata->read_tail;
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci/**
22862306a36Sopenharmony_ci * n_tty_write_wakeup	-	asynchronous I/O notifier
22962306a36Sopenharmony_ci * @tty: tty device
23062306a36Sopenharmony_ci *
23162306a36Sopenharmony_ci * Required for the ptys, serial driver etc. since processes that attach
23262306a36Sopenharmony_ci * themselves to the master and rely on ASYNC IO must be woken up.
23362306a36Sopenharmony_ci */
23462306a36Sopenharmony_cistatic void n_tty_write_wakeup(struct tty_struct *tty)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
23762306a36Sopenharmony_ci	kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic void n_tty_check_throttle(struct tty_struct *tty)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/*
24562306a36Sopenharmony_ci	 * Check the remaining room for the input canonicalization
24662306a36Sopenharmony_ci	 * mode.  We don't want to throttle the driver if we're in
24762306a36Sopenharmony_ci	 * canonical mode and don't have a newline yet!
24862306a36Sopenharmony_ci	 */
24962306a36Sopenharmony_ci	if (ldata->icanon && ldata->canon_head == ldata->read_tail)
25062306a36Sopenharmony_ci		return;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	while (1) {
25362306a36Sopenharmony_ci		int throttled;
25462306a36Sopenharmony_ci		tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
25562306a36Sopenharmony_ci		if (N_TTY_BUF_SIZE - read_cnt(ldata) >= TTY_THRESHOLD_THROTTLE)
25662306a36Sopenharmony_ci			break;
25762306a36Sopenharmony_ci		throttled = tty_throttle_safe(tty);
25862306a36Sopenharmony_ci		if (!throttled)
25962306a36Sopenharmony_ci			break;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci	__tty_set_flow_change(tty, 0);
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic void n_tty_check_unthrottle(struct tty_struct *tty)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
26762306a36Sopenharmony_ci		if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
26862306a36Sopenharmony_ci			return;
26962306a36Sopenharmony_ci		n_tty_kick_worker(tty);
27062306a36Sopenharmony_ci		tty_wakeup(tty->link);
27162306a36Sopenharmony_ci		return;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* If there is enough space in the read buffer now, let the
27562306a36Sopenharmony_ci	 * low-level driver know. We use chars_in_buffer() to
27662306a36Sopenharmony_ci	 * check the buffer, as it now knows about canonical mode.
27762306a36Sopenharmony_ci	 * Otherwise, if the driver is throttled and the line is
27862306a36Sopenharmony_ci	 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
27962306a36Sopenharmony_ci	 * we won't get any more characters.
28062306a36Sopenharmony_ci	 */
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	while (1) {
28362306a36Sopenharmony_ci		int unthrottled;
28462306a36Sopenharmony_ci		tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
28562306a36Sopenharmony_ci		if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
28662306a36Sopenharmony_ci			break;
28762306a36Sopenharmony_ci		n_tty_kick_worker(tty);
28862306a36Sopenharmony_ci		unthrottled = tty_unthrottle_safe(tty);
28962306a36Sopenharmony_ci		if (!unthrottled)
29062306a36Sopenharmony_ci			break;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci	__tty_set_flow_change(tty, 0);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/**
29662306a36Sopenharmony_ci * put_tty_queue		-	add character to tty
29762306a36Sopenharmony_ci * @c: character
29862306a36Sopenharmony_ci * @ldata: n_tty data
29962306a36Sopenharmony_ci *
30062306a36Sopenharmony_ci * Add a character to the tty read_buf queue.
30162306a36Sopenharmony_ci *
30262306a36Sopenharmony_ci * Locking:
30362306a36Sopenharmony_ci *  * n_tty_receive_buf()/producer path:
30462306a36Sopenharmony_ci *	caller holds non-exclusive %termios_rwsem
30562306a36Sopenharmony_ci */
30662306a36Sopenharmony_cistatic inline void put_tty_queue(u8 c, struct n_tty_data *ldata)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	*read_buf_addr(ldata, ldata->read_head) = c;
30962306a36Sopenharmony_ci	ldata->read_head++;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/**
31362306a36Sopenharmony_ci * reset_buffer_flags	-	reset buffer state
31462306a36Sopenharmony_ci * @ldata: line disc data to reset
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci * Reset the read buffer counters and clear the flags. Called from
31762306a36Sopenharmony_ci * n_tty_open() and n_tty_flush_buffer().
31862306a36Sopenharmony_ci *
31962306a36Sopenharmony_ci * Locking:
32062306a36Sopenharmony_ci *  * caller holds exclusive %termios_rwsem, or
32162306a36Sopenharmony_ci *  * (locking is not required)
32262306a36Sopenharmony_ci */
32362306a36Sopenharmony_cistatic void reset_buffer_flags(struct n_tty_data *ldata)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
32662306a36Sopenharmony_ci	ldata->commit_head = 0;
32762306a36Sopenharmony_ci	ldata->line_start = 0;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ldata->erasing = 0;
33062306a36Sopenharmony_ci	bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
33162306a36Sopenharmony_ci	ldata->push = 0;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	ldata->lookahead_count = 0;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic void n_tty_packet_mode_flush(struct tty_struct *tty)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	unsigned long flags;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (tty->link->ctrl.packet) {
34162306a36Sopenharmony_ci		spin_lock_irqsave(&tty->ctrl.lock, flags);
34262306a36Sopenharmony_ci		tty->ctrl.pktstatus |= TIOCPKT_FLUSHREAD;
34362306a36Sopenharmony_ci		spin_unlock_irqrestore(&tty->ctrl.lock, flags);
34462306a36Sopenharmony_ci		wake_up_interruptible(&tty->link->read_wait);
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/**
34962306a36Sopenharmony_ci * n_tty_flush_buffer	-	clean input queue
35062306a36Sopenharmony_ci * @tty: terminal device
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * Flush the input buffer. Called when the tty layer wants the buffer flushed
35362306a36Sopenharmony_ci * (eg at hangup) or when the %N_TTY line discipline internally has to clean
35462306a36Sopenharmony_ci * the pending queue (for example some signals).
35562306a36Sopenharmony_ci *
35662306a36Sopenharmony_ci * Holds %termios_rwsem to exclude producer/consumer while buffer indices are
35762306a36Sopenharmony_ci * reset.
35862306a36Sopenharmony_ci *
35962306a36Sopenharmony_ci * Locking: %ctrl.lock, exclusive %termios_rwsem
36062306a36Sopenharmony_ci */
36162306a36Sopenharmony_cistatic void n_tty_flush_buffer(struct tty_struct *tty)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	down_write(&tty->termios_rwsem);
36462306a36Sopenharmony_ci	reset_buffer_flags(tty->disc_data);
36562306a36Sopenharmony_ci	n_tty_kick_worker(tty);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (tty->link)
36862306a36Sopenharmony_ci		n_tty_packet_mode_flush(tty);
36962306a36Sopenharmony_ci	up_write(&tty->termios_rwsem);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/**
37362306a36Sopenharmony_ci * is_utf8_continuation	-	utf8 multibyte check
37462306a36Sopenharmony_ci * @c: byte to check
37562306a36Sopenharmony_ci *
37662306a36Sopenharmony_ci * Returns: true if the utf8 character @c is a multibyte continuation
37762306a36Sopenharmony_ci * character. We use this to correctly compute the on-screen size of the
37862306a36Sopenharmony_ci * character when printing.
37962306a36Sopenharmony_ci */
38062306a36Sopenharmony_cistatic inline int is_utf8_continuation(u8 c)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	return (c & 0xc0) == 0x80;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci/**
38662306a36Sopenharmony_ci * is_continuation	-	multibyte check
38762306a36Sopenharmony_ci * @c: byte to check
38862306a36Sopenharmony_ci * @tty: terminal device
38962306a36Sopenharmony_ci *
39062306a36Sopenharmony_ci * Returns: true if the utf8 character @c is a multibyte continuation character
39162306a36Sopenharmony_ci * and the terminal is in unicode mode.
39262306a36Sopenharmony_ci */
39362306a36Sopenharmony_cistatic inline int is_continuation(u8 c, const struct tty_struct *tty)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	return I_IUTF8(tty) && is_utf8_continuation(c);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci/**
39962306a36Sopenharmony_ci * do_output_char	-	output one character
40062306a36Sopenharmony_ci * @c: character (or partial unicode symbol)
40162306a36Sopenharmony_ci * @tty: terminal device
40262306a36Sopenharmony_ci * @space: space available in tty driver write buffer
40362306a36Sopenharmony_ci *
40462306a36Sopenharmony_ci * This is a helper function that handles one output character (including
40562306a36Sopenharmony_ci * special characters like TAB, CR, LF, etc.), doing OPOST processing and
40662306a36Sopenharmony_ci * putting the results in the tty driver's write buffer.
40762306a36Sopenharmony_ci *
40862306a36Sopenharmony_ci * Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY and NLDLY.
40962306a36Sopenharmony_ci * They simply aren't relevant in the world today. If you ever need them, add
41062306a36Sopenharmony_ci * them here.
41162306a36Sopenharmony_ci *
41262306a36Sopenharmony_ci * Returns: the number of bytes of buffer space used or -1 if no space left.
41362306a36Sopenharmony_ci *
41462306a36Sopenharmony_ci * Locking: should be called under the %output_lock to protect the column state
41562306a36Sopenharmony_ci * and space left in the buffer.
41662306a36Sopenharmony_ci */
41762306a36Sopenharmony_cistatic int do_output_char(u8 c, struct tty_struct *tty, int space)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
42062306a36Sopenharmony_ci	int	spaces;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (!space)
42362306a36Sopenharmony_ci		return -1;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	switch (c) {
42662306a36Sopenharmony_ci	case '\n':
42762306a36Sopenharmony_ci		if (O_ONLRET(tty))
42862306a36Sopenharmony_ci			ldata->column = 0;
42962306a36Sopenharmony_ci		if (O_ONLCR(tty)) {
43062306a36Sopenharmony_ci			if (space < 2)
43162306a36Sopenharmony_ci				return -1;
43262306a36Sopenharmony_ci			ldata->canon_column = ldata->column = 0;
43362306a36Sopenharmony_ci			tty->ops->write(tty, "\r\n", 2);
43462306a36Sopenharmony_ci			return 2;
43562306a36Sopenharmony_ci		}
43662306a36Sopenharmony_ci		ldata->canon_column = ldata->column;
43762306a36Sopenharmony_ci		break;
43862306a36Sopenharmony_ci	case '\r':
43962306a36Sopenharmony_ci		if (O_ONOCR(tty) && ldata->column == 0)
44062306a36Sopenharmony_ci			return 0;
44162306a36Sopenharmony_ci		if (O_OCRNL(tty)) {
44262306a36Sopenharmony_ci			c = '\n';
44362306a36Sopenharmony_ci			if (O_ONLRET(tty))
44462306a36Sopenharmony_ci				ldata->canon_column = ldata->column = 0;
44562306a36Sopenharmony_ci			break;
44662306a36Sopenharmony_ci		}
44762306a36Sopenharmony_ci		ldata->canon_column = ldata->column = 0;
44862306a36Sopenharmony_ci		break;
44962306a36Sopenharmony_ci	case '\t':
45062306a36Sopenharmony_ci		spaces = 8 - (ldata->column & 7);
45162306a36Sopenharmony_ci		if (O_TABDLY(tty) == XTABS) {
45262306a36Sopenharmony_ci			if (space < spaces)
45362306a36Sopenharmony_ci				return -1;
45462306a36Sopenharmony_ci			ldata->column += spaces;
45562306a36Sopenharmony_ci			tty->ops->write(tty, "        ", spaces);
45662306a36Sopenharmony_ci			return spaces;
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci		ldata->column += spaces;
45962306a36Sopenharmony_ci		break;
46062306a36Sopenharmony_ci	case '\b':
46162306a36Sopenharmony_ci		if (ldata->column > 0)
46262306a36Sopenharmony_ci			ldata->column--;
46362306a36Sopenharmony_ci		break;
46462306a36Sopenharmony_ci	default:
46562306a36Sopenharmony_ci		if (!iscntrl(c)) {
46662306a36Sopenharmony_ci			if (O_OLCUC(tty))
46762306a36Sopenharmony_ci				c = toupper(c);
46862306a36Sopenharmony_ci			if (!is_continuation(c, tty))
46962306a36Sopenharmony_ci				ldata->column++;
47062306a36Sopenharmony_ci		}
47162306a36Sopenharmony_ci		break;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	tty_put_char(tty, c);
47562306a36Sopenharmony_ci	return 1;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/**
47962306a36Sopenharmony_ci * process_output	-	output post processor
48062306a36Sopenharmony_ci * @c: character (or partial unicode symbol)
48162306a36Sopenharmony_ci * @tty: terminal device
48262306a36Sopenharmony_ci *
48362306a36Sopenharmony_ci * Output one character with OPOST processing.
48462306a36Sopenharmony_ci *
48562306a36Sopenharmony_ci * Returns: -1 when the output device is full and the character must be
48662306a36Sopenharmony_ci * retried.
48762306a36Sopenharmony_ci *
48862306a36Sopenharmony_ci * Locking: %output_lock to protect column state and space left (also, this is
48962306a36Sopenharmony_ci *called from n_tty_write() under the tty layer write lock).
49062306a36Sopenharmony_ci */
49162306a36Sopenharmony_cistatic int process_output(u8 c, struct tty_struct *tty)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
49462306a36Sopenharmony_ci	int	space, retval;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	mutex_lock(&ldata->output_lock);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	space = tty_write_room(tty);
49962306a36Sopenharmony_ci	retval = do_output_char(c, tty, space);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	mutex_unlock(&ldata->output_lock);
50262306a36Sopenharmony_ci	if (retval < 0)
50362306a36Sopenharmony_ci		return -1;
50462306a36Sopenharmony_ci	else
50562306a36Sopenharmony_ci		return 0;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/**
50962306a36Sopenharmony_ci * process_output_block	-	block post processor
51062306a36Sopenharmony_ci * @tty: terminal device
51162306a36Sopenharmony_ci * @buf: character buffer
51262306a36Sopenharmony_ci * @nr: number of bytes to output
51362306a36Sopenharmony_ci *
51462306a36Sopenharmony_ci * Output a block of characters with OPOST processing.
51562306a36Sopenharmony_ci *
51662306a36Sopenharmony_ci * This path is used to speed up block console writes, among other things when
51762306a36Sopenharmony_ci * processing blocks of output data. It handles only the simple cases normally
51862306a36Sopenharmony_ci * found and helps to generate blocks of symbols for the console driver and
51962306a36Sopenharmony_ci * thus improve performance.
52062306a36Sopenharmony_ci *
52162306a36Sopenharmony_ci * Returns: the number of characters output.
52262306a36Sopenharmony_ci *
52362306a36Sopenharmony_ci * Locking: %output_lock to protect column state and space left (also, this is
52462306a36Sopenharmony_ci * called from n_tty_write() under the tty layer write lock).
52562306a36Sopenharmony_ci */
52662306a36Sopenharmony_cistatic ssize_t process_output_block(struct tty_struct *tty,
52762306a36Sopenharmony_ci				    const u8 *buf, unsigned int nr)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
53062306a36Sopenharmony_ci	int	space;
53162306a36Sopenharmony_ci	int	i;
53262306a36Sopenharmony_ci	const u8 *cp;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	mutex_lock(&ldata->output_lock);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	space = tty_write_room(tty);
53762306a36Sopenharmony_ci	if (space <= 0) {
53862306a36Sopenharmony_ci		mutex_unlock(&ldata->output_lock);
53962306a36Sopenharmony_ci		return space;
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci	if (nr > space)
54262306a36Sopenharmony_ci		nr = space;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	for (i = 0, cp = buf; i < nr; i++, cp++) {
54562306a36Sopenharmony_ci		u8 c = *cp;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		switch (c) {
54862306a36Sopenharmony_ci		case '\n':
54962306a36Sopenharmony_ci			if (O_ONLRET(tty))
55062306a36Sopenharmony_ci				ldata->column = 0;
55162306a36Sopenharmony_ci			if (O_ONLCR(tty))
55262306a36Sopenharmony_ci				goto break_out;
55362306a36Sopenharmony_ci			ldata->canon_column = ldata->column;
55462306a36Sopenharmony_ci			break;
55562306a36Sopenharmony_ci		case '\r':
55662306a36Sopenharmony_ci			if (O_ONOCR(tty) && ldata->column == 0)
55762306a36Sopenharmony_ci				goto break_out;
55862306a36Sopenharmony_ci			if (O_OCRNL(tty))
55962306a36Sopenharmony_ci				goto break_out;
56062306a36Sopenharmony_ci			ldata->canon_column = ldata->column = 0;
56162306a36Sopenharmony_ci			break;
56262306a36Sopenharmony_ci		case '\t':
56362306a36Sopenharmony_ci			goto break_out;
56462306a36Sopenharmony_ci		case '\b':
56562306a36Sopenharmony_ci			if (ldata->column > 0)
56662306a36Sopenharmony_ci				ldata->column--;
56762306a36Sopenharmony_ci			break;
56862306a36Sopenharmony_ci		default:
56962306a36Sopenharmony_ci			if (!iscntrl(c)) {
57062306a36Sopenharmony_ci				if (O_OLCUC(tty))
57162306a36Sopenharmony_ci					goto break_out;
57262306a36Sopenharmony_ci				if (!is_continuation(c, tty))
57362306a36Sopenharmony_ci					ldata->column++;
57462306a36Sopenharmony_ci			}
57562306a36Sopenharmony_ci			break;
57662306a36Sopenharmony_ci		}
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_cibreak_out:
57962306a36Sopenharmony_ci	i = tty->ops->write(tty, buf, i);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	mutex_unlock(&ldata->output_lock);
58262306a36Sopenharmony_ci	return i;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic int n_tty_process_echo_ops(struct tty_struct *tty, size_t *tail,
58662306a36Sopenharmony_ci				  int space)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
58962306a36Sopenharmony_ci	u8 op;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/*
59262306a36Sopenharmony_ci	 * Since add_echo_byte() is called without holding output_lock, we
59362306a36Sopenharmony_ci	 * might see only portion of multi-byte operation.
59462306a36Sopenharmony_ci	 */
59562306a36Sopenharmony_ci	if (MASK(ldata->echo_commit) == MASK(*tail + 1))
59662306a36Sopenharmony_ci		return -ENODATA;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	/*
59962306a36Sopenharmony_ci	 * If the buffer byte is the start of a multi-byte operation, get the
60062306a36Sopenharmony_ci	 * next byte, which is either the op code or a control character value.
60162306a36Sopenharmony_ci	 */
60262306a36Sopenharmony_ci	op = echo_buf(ldata, *tail + 1);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	switch (op) {
60562306a36Sopenharmony_ci	case ECHO_OP_ERASE_TAB: {
60662306a36Sopenharmony_ci		unsigned int num_chars, num_bs;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		if (MASK(ldata->echo_commit) == MASK(*tail + 2))
60962306a36Sopenharmony_ci			return -ENODATA;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		num_chars = echo_buf(ldata, *tail + 2);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci		/*
61462306a36Sopenharmony_ci		 * Determine how many columns to go back in order to erase the
61562306a36Sopenharmony_ci		 * tab. This depends on the number of columns used by other
61662306a36Sopenharmony_ci		 * characters within the tab area. If this (modulo 8) count is
61762306a36Sopenharmony_ci		 * from the start of input rather than from a previous tab, we
61862306a36Sopenharmony_ci		 * offset by canon column. Otherwise, tab spacing is normal.
61962306a36Sopenharmony_ci		 */
62062306a36Sopenharmony_ci		if (!(num_chars & 0x80))
62162306a36Sopenharmony_ci			num_chars += ldata->canon_column;
62262306a36Sopenharmony_ci		num_bs = 8 - (num_chars & 7);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		if (num_bs > space)
62562306a36Sopenharmony_ci			return -ENOSPC;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci		space -= num_bs;
62862306a36Sopenharmony_ci		while (num_bs--) {
62962306a36Sopenharmony_ci			tty_put_char(tty, '\b');
63062306a36Sopenharmony_ci			if (ldata->column > 0)
63162306a36Sopenharmony_ci				ldata->column--;
63262306a36Sopenharmony_ci		}
63362306a36Sopenharmony_ci		*tail += 3;
63462306a36Sopenharmony_ci		break;
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci	case ECHO_OP_SET_CANON_COL:
63762306a36Sopenharmony_ci		ldata->canon_column = ldata->column;
63862306a36Sopenharmony_ci		*tail += 2;
63962306a36Sopenharmony_ci		break;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	case ECHO_OP_MOVE_BACK_COL:
64262306a36Sopenharmony_ci		if (ldata->column > 0)
64362306a36Sopenharmony_ci			ldata->column--;
64462306a36Sopenharmony_ci		*tail += 2;
64562306a36Sopenharmony_ci		break;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	case ECHO_OP_START:
64862306a36Sopenharmony_ci		/* This is an escaped echo op start code */
64962306a36Sopenharmony_ci		if (!space)
65062306a36Sopenharmony_ci			return -ENOSPC;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci		tty_put_char(tty, ECHO_OP_START);
65362306a36Sopenharmony_ci		ldata->column++;
65462306a36Sopenharmony_ci		space--;
65562306a36Sopenharmony_ci		*tail += 2;
65662306a36Sopenharmony_ci		break;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	default:
65962306a36Sopenharmony_ci		/*
66062306a36Sopenharmony_ci		 * If the op is not a special byte code, it is a ctrl char
66162306a36Sopenharmony_ci		 * tagged to be echoed as "^X" (where X is the letter
66262306a36Sopenharmony_ci		 * representing the control char). Note that we must ensure
66362306a36Sopenharmony_ci		 * there is enough space for the whole ctrl pair.
66462306a36Sopenharmony_ci		 */
66562306a36Sopenharmony_ci		if (space < 2)
66662306a36Sopenharmony_ci			return -ENOSPC;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci		tty_put_char(tty, '^');
66962306a36Sopenharmony_ci		tty_put_char(tty, op ^ 0100);
67062306a36Sopenharmony_ci		ldata->column += 2;
67162306a36Sopenharmony_ci		space -= 2;
67262306a36Sopenharmony_ci		*tail += 2;
67362306a36Sopenharmony_ci		break;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	return space;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci/**
68062306a36Sopenharmony_ci * __process_echoes	-	write pending echo characters
68162306a36Sopenharmony_ci * @tty: terminal device
68262306a36Sopenharmony_ci *
68362306a36Sopenharmony_ci * Write previously buffered echo (and other ldisc-generated) characters to the
68462306a36Sopenharmony_ci * tty.
68562306a36Sopenharmony_ci *
68662306a36Sopenharmony_ci * Characters generated by the ldisc (including echoes) need to be buffered
68762306a36Sopenharmony_ci * because the driver's write buffer can fill during heavy program output.
68862306a36Sopenharmony_ci * Echoing straight to the driver will often fail under these conditions,
68962306a36Sopenharmony_ci * causing lost characters and resulting mismatches of ldisc state information.
69062306a36Sopenharmony_ci *
69162306a36Sopenharmony_ci * Since the ldisc state must represent the characters actually sent to the
69262306a36Sopenharmony_ci * driver at the time of the write, operations like certain changes in column
69362306a36Sopenharmony_ci * state are also saved in the buffer and executed here.
69462306a36Sopenharmony_ci *
69562306a36Sopenharmony_ci * A circular fifo buffer is used so that the most recent characters are
69662306a36Sopenharmony_ci * prioritized. Also, when control characters are echoed with a prefixed "^",
69762306a36Sopenharmony_ci * the pair is treated atomically and thus not separated.
69862306a36Sopenharmony_ci *
69962306a36Sopenharmony_ci * Locking: callers must hold %output_lock.
70062306a36Sopenharmony_ci */
70162306a36Sopenharmony_cistatic size_t __process_echoes(struct tty_struct *tty)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
70462306a36Sopenharmony_ci	int	space, old_space;
70562306a36Sopenharmony_ci	size_t tail;
70662306a36Sopenharmony_ci	u8 c;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	old_space = space = tty_write_room(tty);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	tail = ldata->echo_tail;
71162306a36Sopenharmony_ci	while (MASK(ldata->echo_commit) != MASK(tail)) {
71262306a36Sopenharmony_ci		c = echo_buf(ldata, tail);
71362306a36Sopenharmony_ci		if (c == ECHO_OP_START) {
71462306a36Sopenharmony_ci			int ret = n_tty_process_echo_ops(tty, &tail, space);
71562306a36Sopenharmony_ci			if (ret == -ENODATA)
71662306a36Sopenharmony_ci				goto not_yet_stored;
71762306a36Sopenharmony_ci			if (ret < 0)
71862306a36Sopenharmony_ci				break;
71962306a36Sopenharmony_ci			space = ret;
72062306a36Sopenharmony_ci		} else {
72162306a36Sopenharmony_ci			if (O_OPOST(tty)) {
72262306a36Sopenharmony_ci				int retval = do_output_char(c, tty, space);
72362306a36Sopenharmony_ci				if (retval < 0)
72462306a36Sopenharmony_ci					break;
72562306a36Sopenharmony_ci				space -= retval;
72662306a36Sopenharmony_ci			} else {
72762306a36Sopenharmony_ci				if (!space)
72862306a36Sopenharmony_ci					break;
72962306a36Sopenharmony_ci				tty_put_char(tty, c);
73062306a36Sopenharmony_ci				space -= 1;
73162306a36Sopenharmony_ci			}
73262306a36Sopenharmony_ci			tail += 1;
73362306a36Sopenharmony_ci		}
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	/* If the echo buffer is nearly full (so that the possibility exists
73762306a36Sopenharmony_ci	 * of echo overrun before the next commit), then discard enough
73862306a36Sopenharmony_ci	 * data at the tail to prevent a subsequent overrun */
73962306a36Sopenharmony_ci	while (ldata->echo_commit > tail &&
74062306a36Sopenharmony_ci	       ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
74162306a36Sopenharmony_ci		if (echo_buf(ldata, tail) == ECHO_OP_START) {
74262306a36Sopenharmony_ci			if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB)
74362306a36Sopenharmony_ci				tail += 3;
74462306a36Sopenharmony_ci			else
74562306a36Sopenharmony_ci				tail += 2;
74662306a36Sopenharmony_ci		} else
74762306a36Sopenharmony_ci			tail++;
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci not_yet_stored:
75162306a36Sopenharmony_ci	ldata->echo_tail = tail;
75262306a36Sopenharmony_ci	return old_space - space;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic void commit_echoes(struct tty_struct *tty)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
75862306a36Sopenharmony_ci	size_t nr, old, echoed;
75962306a36Sopenharmony_ci	size_t head;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	mutex_lock(&ldata->output_lock);
76262306a36Sopenharmony_ci	head = ldata->echo_head;
76362306a36Sopenharmony_ci	ldata->echo_mark = head;
76462306a36Sopenharmony_ci	old = ldata->echo_commit - ldata->echo_tail;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	/* Process committed echoes if the accumulated # of bytes
76762306a36Sopenharmony_ci	 * is over the threshold (and try again each time another
76862306a36Sopenharmony_ci	 * block is accumulated) */
76962306a36Sopenharmony_ci	nr = head - ldata->echo_tail;
77062306a36Sopenharmony_ci	if (nr < ECHO_COMMIT_WATERMARK ||
77162306a36Sopenharmony_ci	    (nr % ECHO_BLOCK > old % ECHO_BLOCK)) {
77262306a36Sopenharmony_ci		mutex_unlock(&ldata->output_lock);
77362306a36Sopenharmony_ci		return;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	ldata->echo_commit = head;
77762306a36Sopenharmony_ci	echoed = __process_echoes(tty);
77862306a36Sopenharmony_ci	mutex_unlock(&ldata->output_lock);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	if (echoed && tty->ops->flush_chars)
78162306a36Sopenharmony_ci		tty->ops->flush_chars(tty);
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistatic void process_echoes(struct tty_struct *tty)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
78762306a36Sopenharmony_ci	size_t echoed;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	if (ldata->echo_mark == ldata->echo_tail)
79062306a36Sopenharmony_ci		return;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	mutex_lock(&ldata->output_lock);
79362306a36Sopenharmony_ci	ldata->echo_commit = ldata->echo_mark;
79462306a36Sopenharmony_ci	echoed = __process_echoes(tty);
79562306a36Sopenharmony_ci	mutex_unlock(&ldata->output_lock);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (echoed && tty->ops->flush_chars)
79862306a36Sopenharmony_ci		tty->ops->flush_chars(tty);
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci/* NB: echo_mark and echo_head should be equivalent here */
80262306a36Sopenharmony_cistatic void flush_echoes(struct tty_struct *tty)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if ((!L_ECHO(tty) && !L_ECHONL(tty)) ||
80762306a36Sopenharmony_ci	    ldata->echo_commit == ldata->echo_head)
80862306a36Sopenharmony_ci		return;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	mutex_lock(&ldata->output_lock);
81162306a36Sopenharmony_ci	ldata->echo_commit = ldata->echo_head;
81262306a36Sopenharmony_ci	__process_echoes(tty);
81362306a36Sopenharmony_ci	mutex_unlock(&ldata->output_lock);
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/**
81762306a36Sopenharmony_ci * add_echo_byte	-	add a byte to the echo buffer
81862306a36Sopenharmony_ci * @c: unicode byte to echo
81962306a36Sopenharmony_ci * @ldata: n_tty data
82062306a36Sopenharmony_ci *
82162306a36Sopenharmony_ci * Add a character or operation byte to the echo buffer.
82262306a36Sopenharmony_ci */
82362306a36Sopenharmony_cistatic inline void add_echo_byte(u8 c, struct n_tty_data *ldata)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	*echo_buf_addr(ldata, ldata->echo_head) = c;
82662306a36Sopenharmony_ci	smp_wmb(); /* Matches smp_rmb() in echo_buf(). */
82762306a36Sopenharmony_ci	ldata->echo_head++;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci/**
83162306a36Sopenharmony_ci * echo_move_back_col	-	add operation to move back a column
83262306a36Sopenharmony_ci * @ldata: n_tty data
83362306a36Sopenharmony_ci *
83462306a36Sopenharmony_ci * Add an operation to the echo buffer to move back one column.
83562306a36Sopenharmony_ci */
83662306a36Sopenharmony_cistatic void echo_move_back_col(struct n_tty_data *ldata)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	add_echo_byte(ECHO_OP_START, ldata);
83962306a36Sopenharmony_ci	add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata);
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci/**
84362306a36Sopenharmony_ci * echo_set_canon_col	-	add operation to set the canon column
84462306a36Sopenharmony_ci * @ldata: n_tty data
84562306a36Sopenharmony_ci *
84662306a36Sopenharmony_ci * Add an operation to the echo buffer to set the canon column to the current
84762306a36Sopenharmony_ci * column.
84862306a36Sopenharmony_ci */
84962306a36Sopenharmony_cistatic void echo_set_canon_col(struct n_tty_data *ldata)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	add_echo_byte(ECHO_OP_START, ldata);
85262306a36Sopenharmony_ci	add_echo_byte(ECHO_OP_SET_CANON_COL, ldata);
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci/**
85662306a36Sopenharmony_ci * echo_erase_tab	-	add operation to erase a tab
85762306a36Sopenharmony_ci * @num_chars: number of character columns already used
85862306a36Sopenharmony_ci * @after_tab: true if num_chars starts after a previous tab
85962306a36Sopenharmony_ci * @ldata: n_tty data
86062306a36Sopenharmony_ci *
86162306a36Sopenharmony_ci * Add an operation to the echo buffer to erase a tab.
86262306a36Sopenharmony_ci *
86362306a36Sopenharmony_ci * Called by the eraser function, which knows how many character columns have
86462306a36Sopenharmony_ci * been used since either a previous tab or the start of input. This
86562306a36Sopenharmony_ci * information will be used later, along with canon column (if applicable), to
86662306a36Sopenharmony_ci * go back the correct number of columns.
86762306a36Sopenharmony_ci */
86862306a36Sopenharmony_cistatic void echo_erase_tab(unsigned int num_chars, int after_tab,
86962306a36Sopenharmony_ci			   struct n_tty_data *ldata)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	add_echo_byte(ECHO_OP_START, ldata);
87262306a36Sopenharmony_ci	add_echo_byte(ECHO_OP_ERASE_TAB, ldata);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	/* We only need to know this modulo 8 (tab spacing) */
87562306a36Sopenharmony_ci	num_chars &= 7;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* Set the high bit as a flag if num_chars is after a previous tab */
87862306a36Sopenharmony_ci	if (after_tab)
87962306a36Sopenharmony_ci		num_chars |= 0x80;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	add_echo_byte(num_chars, ldata);
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci/**
88562306a36Sopenharmony_ci * echo_char_raw	-	echo a character raw
88662306a36Sopenharmony_ci * @c: unicode byte to echo
88762306a36Sopenharmony_ci * @ldata: line disc data
88862306a36Sopenharmony_ci *
88962306a36Sopenharmony_ci * Echo user input back onto the screen. This must be called only when
89062306a36Sopenharmony_ci * L_ECHO(tty) is true. Called from the &tty_driver.receive_buf() path.
89162306a36Sopenharmony_ci *
89262306a36Sopenharmony_ci * This variant does not treat control characters specially.
89362306a36Sopenharmony_ci */
89462306a36Sopenharmony_cistatic void echo_char_raw(u8 c, struct n_tty_data *ldata)
89562306a36Sopenharmony_ci{
89662306a36Sopenharmony_ci	if (c == ECHO_OP_START) {
89762306a36Sopenharmony_ci		add_echo_byte(ECHO_OP_START, ldata);
89862306a36Sopenharmony_ci		add_echo_byte(ECHO_OP_START, ldata);
89962306a36Sopenharmony_ci	} else {
90062306a36Sopenharmony_ci		add_echo_byte(c, ldata);
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci/**
90562306a36Sopenharmony_ci * echo_char		-	echo a character
90662306a36Sopenharmony_ci * @c: unicode byte to echo
90762306a36Sopenharmony_ci * @tty: terminal device
90862306a36Sopenharmony_ci *
90962306a36Sopenharmony_ci * Echo user input back onto the screen. This must be called only when
91062306a36Sopenharmony_ci * L_ECHO(tty) is true. Called from the &tty_driver.receive_buf() path.
91162306a36Sopenharmony_ci *
91262306a36Sopenharmony_ci * This variant tags control characters to be echoed as "^X" (where X is the
91362306a36Sopenharmony_ci * letter representing the control char).
91462306a36Sopenharmony_ci */
91562306a36Sopenharmony_cistatic void echo_char(u8 c, const struct tty_struct *tty)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	if (c == ECHO_OP_START) {
92062306a36Sopenharmony_ci		add_echo_byte(ECHO_OP_START, ldata);
92162306a36Sopenharmony_ci		add_echo_byte(ECHO_OP_START, ldata);
92262306a36Sopenharmony_ci	} else {
92362306a36Sopenharmony_ci		if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
92462306a36Sopenharmony_ci			add_echo_byte(ECHO_OP_START, ldata);
92562306a36Sopenharmony_ci		add_echo_byte(c, ldata);
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci/**
93062306a36Sopenharmony_ci * finish_erasing	-	complete erase
93162306a36Sopenharmony_ci * @ldata: n_tty data
93262306a36Sopenharmony_ci */
93362306a36Sopenharmony_cistatic inline void finish_erasing(struct n_tty_data *ldata)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci	if (ldata->erasing) {
93662306a36Sopenharmony_ci		echo_char_raw('/', ldata);
93762306a36Sopenharmony_ci		ldata->erasing = 0;
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci/**
94262306a36Sopenharmony_ci * eraser		-	handle erase function
94362306a36Sopenharmony_ci * @c: character input
94462306a36Sopenharmony_ci * @tty: terminal device
94562306a36Sopenharmony_ci *
94662306a36Sopenharmony_ci * Perform erase and necessary output when an erase character is present in the
94762306a36Sopenharmony_ci * stream from the driver layer. Handles the complexities of UTF-8 multibyte
94862306a36Sopenharmony_ci * symbols.
94962306a36Sopenharmony_ci *
95062306a36Sopenharmony_ci * Locking: n_tty_receive_buf()/producer path:
95162306a36Sopenharmony_ci *	caller holds non-exclusive %termios_rwsem
95262306a36Sopenharmony_ci */
95362306a36Sopenharmony_cistatic void eraser(u8 c, const struct tty_struct *tty)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
95662306a36Sopenharmony_ci	enum { ERASE, WERASE, KILL } kill_type;
95762306a36Sopenharmony_ci	size_t head;
95862306a36Sopenharmony_ci	size_t cnt;
95962306a36Sopenharmony_ci	int seen_alnums;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	if (ldata->read_head == ldata->canon_head) {
96262306a36Sopenharmony_ci		/* process_output('\a', tty); */ /* what do you think? */
96362306a36Sopenharmony_ci		return;
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci	if (c == ERASE_CHAR(tty))
96662306a36Sopenharmony_ci		kill_type = ERASE;
96762306a36Sopenharmony_ci	else if (c == WERASE_CHAR(tty))
96862306a36Sopenharmony_ci		kill_type = WERASE;
96962306a36Sopenharmony_ci	else {
97062306a36Sopenharmony_ci		if (!L_ECHO(tty)) {
97162306a36Sopenharmony_ci			ldata->read_head = ldata->canon_head;
97262306a36Sopenharmony_ci			return;
97362306a36Sopenharmony_ci		}
97462306a36Sopenharmony_ci		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
97562306a36Sopenharmony_ci			ldata->read_head = ldata->canon_head;
97662306a36Sopenharmony_ci			finish_erasing(ldata);
97762306a36Sopenharmony_ci			echo_char(KILL_CHAR(tty), tty);
97862306a36Sopenharmony_ci			/* Add a newline if ECHOK is on and ECHOKE is off. */
97962306a36Sopenharmony_ci			if (L_ECHOK(tty))
98062306a36Sopenharmony_ci				echo_char_raw('\n', ldata);
98162306a36Sopenharmony_ci			return;
98262306a36Sopenharmony_ci		}
98362306a36Sopenharmony_ci		kill_type = KILL;
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	seen_alnums = 0;
98762306a36Sopenharmony_ci	while (MASK(ldata->read_head) != MASK(ldata->canon_head)) {
98862306a36Sopenharmony_ci		head = ldata->read_head;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci		/* erase a single possibly multibyte character */
99162306a36Sopenharmony_ci		do {
99262306a36Sopenharmony_ci			head--;
99362306a36Sopenharmony_ci			c = read_buf(ldata, head);
99462306a36Sopenharmony_ci		} while (is_continuation(c, tty) &&
99562306a36Sopenharmony_ci			 MASK(head) != MASK(ldata->canon_head));
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci		/* do not partially erase */
99862306a36Sopenharmony_ci		if (is_continuation(c, tty))
99962306a36Sopenharmony_ci			break;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci		if (kill_type == WERASE) {
100262306a36Sopenharmony_ci			/* Equivalent to BSD's ALTWERASE. */
100362306a36Sopenharmony_ci			if (isalnum(c) || c == '_')
100462306a36Sopenharmony_ci				seen_alnums++;
100562306a36Sopenharmony_ci			else if (seen_alnums)
100662306a36Sopenharmony_ci				break;
100762306a36Sopenharmony_ci		}
100862306a36Sopenharmony_ci		cnt = ldata->read_head - head;
100962306a36Sopenharmony_ci		ldata->read_head = head;
101062306a36Sopenharmony_ci		if (L_ECHO(tty)) {
101162306a36Sopenharmony_ci			if (L_ECHOPRT(tty)) {
101262306a36Sopenharmony_ci				if (!ldata->erasing) {
101362306a36Sopenharmony_ci					echo_char_raw('\\', ldata);
101462306a36Sopenharmony_ci					ldata->erasing = 1;
101562306a36Sopenharmony_ci				}
101662306a36Sopenharmony_ci				/* if cnt > 1, output a multi-byte character */
101762306a36Sopenharmony_ci				echo_char(c, tty);
101862306a36Sopenharmony_ci				while (--cnt > 0) {
101962306a36Sopenharmony_ci					head++;
102062306a36Sopenharmony_ci					echo_char_raw(read_buf(ldata, head), ldata);
102162306a36Sopenharmony_ci					echo_move_back_col(ldata);
102262306a36Sopenharmony_ci				}
102362306a36Sopenharmony_ci			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
102462306a36Sopenharmony_ci				echo_char(ERASE_CHAR(tty), tty);
102562306a36Sopenharmony_ci			} else if (c == '\t') {
102662306a36Sopenharmony_ci				unsigned int num_chars = 0;
102762306a36Sopenharmony_ci				int after_tab = 0;
102862306a36Sopenharmony_ci				size_t tail = ldata->read_head;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci				/*
103162306a36Sopenharmony_ci				 * Count the columns used for characters
103262306a36Sopenharmony_ci				 * since the start of input or after a
103362306a36Sopenharmony_ci				 * previous tab.
103462306a36Sopenharmony_ci				 * This info is used to go back the correct
103562306a36Sopenharmony_ci				 * number of columns.
103662306a36Sopenharmony_ci				 */
103762306a36Sopenharmony_ci				while (MASK(tail) != MASK(ldata->canon_head)) {
103862306a36Sopenharmony_ci					tail--;
103962306a36Sopenharmony_ci					c = read_buf(ldata, tail);
104062306a36Sopenharmony_ci					if (c == '\t') {
104162306a36Sopenharmony_ci						after_tab = 1;
104262306a36Sopenharmony_ci						break;
104362306a36Sopenharmony_ci					} else if (iscntrl(c)) {
104462306a36Sopenharmony_ci						if (L_ECHOCTL(tty))
104562306a36Sopenharmony_ci							num_chars += 2;
104662306a36Sopenharmony_ci					} else if (!is_continuation(c, tty)) {
104762306a36Sopenharmony_ci						num_chars++;
104862306a36Sopenharmony_ci					}
104962306a36Sopenharmony_ci				}
105062306a36Sopenharmony_ci				echo_erase_tab(num_chars, after_tab, ldata);
105162306a36Sopenharmony_ci			} else {
105262306a36Sopenharmony_ci				if (iscntrl(c) && L_ECHOCTL(tty)) {
105362306a36Sopenharmony_ci					echo_char_raw('\b', ldata);
105462306a36Sopenharmony_ci					echo_char_raw(' ', ldata);
105562306a36Sopenharmony_ci					echo_char_raw('\b', ldata);
105662306a36Sopenharmony_ci				}
105762306a36Sopenharmony_ci				if (!iscntrl(c) || L_ECHOCTL(tty)) {
105862306a36Sopenharmony_ci					echo_char_raw('\b', ldata);
105962306a36Sopenharmony_ci					echo_char_raw(' ', ldata);
106062306a36Sopenharmony_ci					echo_char_raw('\b', ldata);
106162306a36Sopenharmony_ci				}
106262306a36Sopenharmony_ci			}
106362306a36Sopenharmony_ci		}
106462306a36Sopenharmony_ci		if (kill_type == ERASE)
106562306a36Sopenharmony_ci			break;
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci	if (ldata->read_head == ldata->canon_head && L_ECHO(tty))
106862306a36Sopenharmony_ci		finish_erasing(ldata);
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic void __isig(int sig, struct tty_struct *tty)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	struct pid *tty_pgrp = tty_get_pgrp(tty);
107562306a36Sopenharmony_ci	if (tty_pgrp) {
107662306a36Sopenharmony_ci		kill_pgrp(tty_pgrp, sig, 1);
107762306a36Sopenharmony_ci		put_pid(tty_pgrp);
107862306a36Sopenharmony_ci	}
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci/**
108262306a36Sopenharmony_ci * isig			-	handle the ISIG optio
108362306a36Sopenharmony_ci * @sig: signal
108462306a36Sopenharmony_ci * @tty: terminal
108562306a36Sopenharmony_ci *
108662306a36Sopenharmony_ci * Called when a signal is being sent due to terminal input. Called from the
108762306a36Sopenharmony_ci * &tty_driver.receive_buf() path, so serialized.
108862306a36Sopenharmony_ci *
108962306a36Sopenharmony_ci * Performs input and output flush if !NOFLSH. In this context, the echo
109062306a36Sopenharmony_ci * buffer is 'output'. The signal is processed first to alert any current
109162306a36Sopenharmony_ci * readers or writers to discontinue and exit their i/o loops.
109262306a36Sopenharmony_ci *
109362306a36Sopenharmony_ci * Locking: %ctrl.lock
109462306a36Sopenharmony_ci */
109562306a36Sopenharmony_cistatic void isig(int sig, struct tty_struct *tty)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	if (L_NOFLSH(tty)) {
110062306a36Sopenharmony_ci		/* signal only */
110162306a36Sopenharmony_ci		__isig(sig, tty);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	} else { /* signal and flush */
110462306a36Sopenharmony_ci		up_read(&tty->termios_rwsem);
110562306a36Sopenharmony_ci		down_write(&tty->termios_rwsem);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci		__isig(sig, tty);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci		/* clear echo buffer */
111062306a36Sopenharmony_ci		mutex_lock(&ldata->output_lock);
111162306a36Sopenharmony_ci		ldata->echo_head = ldata->echo_tail = 0;
111262306a36Sopenharmony_ci		ldata->echo_mark = ldata->echo_commit = 0;
111362306a36Sopenharmony_ci		mutex_unlock(&ldata->output_lock);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci		/* clear output buffer */
111662306a36Sopenharmony_ci		tty_driver_flush_buffer(tty);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci		/* clear input buffer */
111962306a36Sopenharmony_ci		reset_buffer_flags(tty->disc_data);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci		/* notify pty master of flush */
112262306a36Sopenharmony_ci		if (tty->link)
112362306a36Sopenharmony_ci			n_tty_packet_mode_flush(tty);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci		up_write(&tty->termios_rwsem);
112662306a36Sopenharmony_ci		down_read(&tty->termios_rwsem);
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci/**
113162306a36Sopenharmony_ci * n_tty_receive_break	-	handle break
113262306a36Sopenharmony_ci * @tty: terminal
113362306a36Sopenharmony_ci *
113462306a36Sopenharmony_ci * An RS232 break event has been hit in the incoming bitstream. This can cause
113562306a36Sopenharmony_ci * a variety of events depending upon the termios settings.
113662306a36Sopenharmony_ci *
113762306a36Sopenharmony_ci * Locking: n_tty_receive_buf()/producer path:
113862306a36Sopenharmony_ci *	caller holds non-exclusive termios_rwsem
113962306a36Sopenharmony_ci *
114062306a36Sopenharmony_ci * Note: may get exclusive %termios_rwsem if flushing input buffer
114162306a36Sopenharmony_ci */
114262306a36Sopenharmony_cistatic void n_tty_receive_break(struct tty_struct *tty)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	if (I_IGNBRK(tty))
114762306a36Sopenharmony_ci		return;
114862306a36Sopenharmony_ci	if (I_BRKINT(tty)) {
114962306a36Sopenharmony_ci		isig(SIGINT, tty);
115062306a36Sopenharmony_ci		return;
115162306a36Sopenharmony_ci	}
115262306a36Sopenharmony_ci	if (I_PARMRK(tty)) {
115362306a36Sopenharmony_ci		put_tty_queue('\377', ldata);
115462306a36Sopenharmony_ci		put_tty_queue('\0', ldata);
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci	put_tty_queue('\0', ldata);
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci/**
116062306a36Sopenharmony_ci * n_tty_receive_overrun	-	handle overrun reporting
116162306a36Sopenharmony_ci * @tty: terminal
116262306a36Sopenharmony_ci *
116362306a36Sopenharmony_ci * Data arrived faster than we could process it. While the tty driver has
116462306a36Sopenharmony_ci * flagged this the bits that were missed are gone forever.
116562306a36Sopenharmony_ci *
116662306a36Sopenharmony_ci * Called from the receive_buf path so single threaded. Does not need locking
116762306a36Sopenharmony_ci * as num_overrun and overrun_time are function private.
116862306a36Sopenharmony_ci */
116962306a36Sopenharmony_cistatic void n_tty_receive_overrun(const struct tty_struct *tty)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	ldata->num_overrun++;
117462306a36Sopenharmony_ci	if (time_is_before_jiffies(ldata->overrun_time + HZ)) {
117562306a36Sopenharmony_ci		tty_warn(tty, "%u input overrun(s)\n", ldata->num_overrun);
117662306a36Sopenharmony_ci		ldata->overrun_time = jiffies;
117762306a36Sopenharmony_ci		ldata->num_overrun = 0;
117862306a36Sopenharmony_ci	}
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci/**
118262306a36Sopenharmony_ci * n_tty_receive_parity_error	-	error notifier
118362306a36Sopenharmony_ci * @tty: terminal device
118462306a36Sopenharmony_ci * @c: character
118562306a36Sopenharmony_ci *
118662306a36Sopenharmony_ci * Process a parity error and queue the right data to indicate the error case
118762306a36Sopenharmony_ci * if necessary.
118862306a36Sopenharmony_ci *
118962306a36Sopenharmony_ci * Locking: n_tty_receive_buf()/producer path:
119062306a36Sopenharmony_ci * 	caller holds non-exclusive %termios_rwsem
119162306a36Sopenharmony_ci */
119262306a36Sopenharmony_cistatic void n_tty_receive_parity_error(const struct tty_struct *tty,
119362306a36Sopenharmony_ci				       u8 c)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	if (I_INPCK(tty)) {
119862306a36Sopenharmony_ci		if (I_IGNPAR(tty))
119962306a36Sopenharmony_ci			return;
120062306a36Sopenharmony_ci		if (I_PARMRK(tty)) {
120162306a36Sopenharmony_ci			put_tty_queue('\377', ldata);
120262306a36Sopenharmony_ci			put_tty_queue('\0', ldata);
120362306a36Sopenharmony_ci			put_tty_queue(c, ldata);
120462306a36Sopenharmony_ci		} else
120562306a36Sopenharmony_ci			put_tty_queue('\0', ldata);
120662306a36Sopenharmony_ci	} else
120762306a36Sopenharmony_ci		put_tty_queue(c, ldata);
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_cistatic void
121162306a36Sopenharmony_cin_tty_receive_signal_char(struct tty_struct *tty, int signal, u8 c)
121262306a36Sopenharmony_ci{
121362306a36Sopenharmony_ci	isig(signal, tty);
121462306a36Sopenharmony_ci	if (I_IXON(tty))
121562306a36Sopenharmony_ci		start_tty(tty);
121662306a36Sopenharmony_ci	if (L_ECHO(tty)) {
121762306a36Sopenharmony_ci		echo_char(c, tty);
121862306a36Sopenharmony_ci		commit_echoes(tty);
121962306a36Sopenharmony_ci	} else
122062306a36Sopenharmony_ci		process_echoes(tty);
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic bool n_tty_is_char_flow_ctrl(struct tty_struct *tty, u8 c)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	return c == START_CHAR(tty) || c == STOP_CHAR(tty);
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci/**
122962306a36Sopenharmony_ci * n_tty_receive_char_flow_ctrl - receive flow control chars
123062306a36Sopenharmony_ci * @tty: terminal device
123162306a36Sopenharmony_ci * @c: character
123262306a36Sopenharmony_ci * @lookahead_done: lookahead has processed this character already
123362306a36Sopenharmony_ci *
123462306a36Sopenharmony_ci * Receive and process flow control character actions.
123562306a36Sopenharmony_ci *
123662306a36Sopenharmony_ci * In case lookahead for flow control chars already handled the character in
123762306a36Sopenharmony_ci * advance to the normal receive, the actions are skipped during normal
123862306a36Sopenharmony_ci * receive.
123962306a36Sopenharmony_ci *
124062306a36Sopenharmony_ci * Returns true if @c is consumed as flow-control character, the character
124162306a36Sopenharmony_ci * must not be treated as normal character.
124262306a36Sopenharmony_ci */
124362306a36Sopenharmony_cistatic bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, u8 c,
124462306a36Sopenharmony_ci					 bool lookahead_done)
124562306a36Sopenharmony_ci{
124662306a36Sopenharmony_ci	if (!n_tty_is_char_flow_ctrl(tty, c))
124762306a36Sopenharmony_ci		return false;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	if (lookahead_done)
125062306a36Sopenharmony_ci		return true;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	if (c == START_CHAR(tty)) {
125362306a36Sopenharmony_ci		start_tty(tty);
125462306a36Sopenharmony_ci		process_echoes(tty);
125562306a36Sopenharmony_ci		return true;
125662306a36Sopenharmony_ci	}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	/* STOP_CHAR */
125962306a36Sopenharmony_ci	stop_tty(tty);
126062306a36Sopenharmony_ci	return true;
126162306a36Sopenharmony_ci}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_cistatic void n_tty_receive_handle_newline(struct tty_struct *tty, u8 c)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	set_bit(MASK(ldata->read_head), ldata->read_flags);
126862306a36Sopenharmony_ci	put_tty_queue(c, ldata);
126962306a36Sopenharmony_ci	smp_store_release(&ldata->canon_head, ldata->read_head);
127062306a36Sopenharmony_ci	kill_fasync(&tty->fasync, SIGIO, POLL_IN);
127162306a36Sopenharmony_ci	wake_up_interruptible_poll(&tty->read_wait, EPOLLIN | EPOLLRDNORM);
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic bool n_tty_receive_char_canon(struct tty_struct *tty, u8 c)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
127962306a36Sopenharmony_ci	    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
128062306a36Sopenharmony_ci		eraser(c, tty);
128162306a36Sopenharmony_ci		commit_echoes(tty);
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci		return true;
128462306a36Sopenharmony_ci	}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
128762306a36Sopenharmony_ci		ldata->lnext = 1;
128862306a36Sopenharmony_ci		if (L_ECHO(tty)) {
128962306a36Sopenharmony_ci			finish_erasing(ldata);
129062306a36Sopenharmony_ci			if (L_ECHOCTL(tty)) {
129162306a36Sopenharmony_ci				echo_char_raw('^', ldata);
129262306a36Sopenharmony_ci				echo_char_raw('\b', ldata);
129362306a36Sopenharmony_ci				commit_echoes(tty);
129462306a36Sopenharmony_ci			}
129562306a36Sopenharmony_ci		}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci		return true;
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) {
130162306a36Sopenharmony_ci		size_t tail = ldata->canon_head;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci		finish_erasing(ldata);
130462306a36Sopenharmony_ci		echo_char(c, tty);
130562306a36Sopenharmony_ci		echo_char_raw('\n', ldata);
130662306a36Sopenharmony_ci		while (MASK(tail) != MASK(ldata->read_head)) {
130762306a36Sopenharmony_ci			echo_char(read_buf(ldata, tail), tty);
130862306a36Sopenharmony_ci			tail++;
130962306a36Sopenharmony_ci		}
131062306a36Sopenharmony_ci		commit_echoes(tty);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci		return true;
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	if (c == '\n') {
131662306a36Sopenharmony_ci		if (L_ECHO(tty) || L_ECHONL(tty)) {
131762306a36Sopenharmony_ci			echo_char_raw('\n', ldata);
131862306a36Sopenharmony_ci			commit_echoes(tty);
131962306a36Sopenharmony_ci		}
132062306a36Sopenharmony_ci		n_tty_receive_handle_newline(tty, c);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		return true;
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	if (c == EOF_CHAR(tty)) {
132662306a36Sopenharmony_ci		c = __DISABLED_CHAR;
132762306a36Sopenharmony_ci		n_tty_receive_handle_newline(tty, c);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci		return true;
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	if ((c == EOL_CHAR(tty)) ||
133362306a36Sopenharmony_ci	    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
133462306a36Sopenharmony_ci		/*
133562306a36Sopenharmony_ci		 * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
133662306a36Sopenharmony_ci		 */
133762306a36Sopenharmony_ci		if (L_ECHO(tty)) {
133862306a36Sopenharmony_ci			/* Record the column of first canon char. */
133962306a36Sopenharmony_ci			if (ldata->canon_head == ldata->read_head)
134062306a36Sopenharmony_ci				echo_set_canon_col(ldata);
134162306a36Sopenharmony_ci			echo_char(c, tty);
134262306a36Sopenharmony_ci			commit_echoes(tty);
134362306a36Sopenharmony_ci		}
134462306a36Sopenharmony_ci		/*
134562306a36Sopenharmony_ci		 * XXX does PARMRK doubling happen for
134662306a36Sopenharmony_ci		 * EOL_CHAR and EOL2_CHAR?
134762306a36Sopenharmony_ci		 */
134862306a36Sopenharmony_ci		if (c == '\377' && I_PARMRK(tty))
134962306a36Sopenharmony_ci			put_tty_queue(c, ldata);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci		n_tty_receive_handle_newline(tty, c);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci		return true;
135462306a36Sopenharmony_ci	}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	return false;
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_cistatic void n_tty_receive_char_special(struct tty_struct *tty, u8 c,
136062306a36Sopenharmony_ci				       bool lookahead_done)
136162306a36Sopenharmony_ci{
136262306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c, lookahead_done))
136562306a36Sopenharmony_ci		return;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	if (L_ISIG(tty)) {
136862306a36Sopenharmony_ci		if (c == INTR_CHAR(tty)) {
136962306a36Sopenharmony_ci			n_tty_receive_signal_char(tty, SIGINT, c);
137062306a36Sopenharmony_ci			return;
137162306a36Sopenharmony_ci		} else if (c == QUIT_CHAR(tty)) {
137262306a36Sopenharmony_ci			n_tty_receive_signal_char(tty, SIGQUIT, c);
137362306a36Sopenharmony_ci			return;
137462306a36Sopenharmony_ci		} else if (c == SUSP_CHAR(tty)) {
137562306a36Sopenharmony_ci			n_tty_receive_signal_char(tty, SIGTSTP, c);
137662306a36Sopenharmony_ci			return;
137762306a36Sopenharmony_ci		}
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) {
138162306a36Sopenharmony_ci		start_tty(tty);
138262306a36Sopenharmony_ci		process_echoes(tty);
138362306a36Sopenharmony_ci	}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	if (c == '\r') {
138662306a36Sopenharmony_ci		if (I_IGNCR(tty))
138762306a36Sopenharmony_ci			return;
138862306a36Sopenharmony_ci		if (I_ICRNL(tty))
138962306a36Sopenharmony_ci			c = '\n';
139062306a36Sopenharmony_ci	} else if (c == '\n' && I_INLCR(tty))
139162306a36Sopenharmony_ci		c = '\r';
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	if (ldata->icanon && n_tty_receive_char_canon(tty, c))
139462306a36Sopenharmony_ci		return;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (L_ECHO(tty)) {
139762306a36Sopenharmony_ci		finish_erasing(ldata);
139862306a36Sopenharmony_ci		if (c == '\n')
139962306a36Sopenharmony_ci			echo_char_raw('\n', ldata);
140062306a36Sopenharmony_ci		else {
140162306a36Sopenharmony_ci			/* Record the column of first canon char. */
140262306a36Sopenharmony_ci			if (ldata->canon_head == ldata->read_head)
140362306a36Sopenharmony_ci				echo_set_canon_col(ldata);
140462306a36Sopenharmony_ci			echo_char(c, tty);
140562306a36Sopenharmony_ci		}
140662306a36Sopenharmony_ci		commit_echoes(tty);
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/* PARMRK doubling check */
141062306a36Sopenharmony_ci	if (c == '\377' && I_PARMRK(tty))
141162306a36Sopenharmony_ci		put_tty_queue(c, ldata);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	put_tty_queue(c, ldata);
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci/**
141762306a36Sopenharmony_ci * n_tty_receive_char	-	perform processing
141862306a36Sopenharmony_ci * @tty: terminal device
141962306a36Sopenharmony_ci * @c: character
142062306a36Sopenharmony_ci *
142162306a36Sopenharmony_ci * Process an individual character of input received from the driver.  This is
142262306a36Sopenharmony_ci * serialized with respect to itself by the rules for the driver above.
142362306a36Sopenharmony_ci *
142462306a36Sopenharmony_ci * Locking: n_tty_receive_buf()/producer path:
142562306a36Sopenharmony_ci *	caller holds non-exclusive %termios_rwsem
142662306a36Sopenharmony_ci *	publishes canon_head if canonical mode is active
142762306a36Sopenharmony_ci */
142862306a36Sopenharmony_cistatic void n_tty_receive_char(struct tty_struct *tty, u8 c)
142962306a36Sopenharmony_ci{
143062306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) {
143362306a36Sopenharmony_ci		start_tty(tty);
143462306a36Sopenharmony_ci		process_echoes(tty);
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci	if (L_ECHO(tty)) {
143762306a36Sopenharmony_ci		finish_erasing(ldata);
143862306a36Sopenharmony_ci		/* Record the column of first canon char. */
143962306a36Sopenharmony_ci		if (ldata->canon_head == ldata->read_head)
144062306a36Sopenharmony_ci			echo_set_canon_col(ldata);
144162306a36Sopenharmony_ci		echo_char(c, tty);
144262306a36Sopenharmony_ci		commit_echoes(tty);
144362306a36Sopenharmony_ci	}
144462306a36Sopenharmony_ci	/* PARMRK doubling check */
144562306a36Sopenharmony_ci	if (c == '\377' && I_PARMRK(tty))
144662306a36Sopenharmony_ci		put_tty_queue(c, ldata);
144762306a36Sopenharmony_ci	put_tty_queue(c, ldata);
144862306a36Sopenharmony_ci}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_cistatic void n_tty_receive_char_closing(struct tty_struct *tty, u8 c,
145162306a36Sopenharmony_ci				       bool lookahead_done)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	if (I_ISTRIP(tty))
145462306a36Sopenharmony_ci		c &= 0x7f;
145562306a36Sopenharmony_ci	if (I_IUCLC(tty) && L_IEXTEN(tty))
145662306a36Sopenharmony_ci		c = tolower(c);
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	if (I_IXON(tty)) {
145962306a36Sopenharmony_ci		if (!n_tty_receive_char_flow_ctrl(tty, c, lookahead_done) &&
146062306a36Sopenharmony_ci		    tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) &&
146162306a36Sopenharmony_ci		    c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
146262306a36Sopenharmony_ci		    c != SUSP_CHAR(tty)) {
146362306a36Sopenharmony_ci			start_tty(tty);
146462306a36Sopenharmony_ci			process_echoes(tty);
146562306a36Sopenharmony_ci		}
146662306a36Sopenharmony_ci	}
146762306a36Sopenharmony_ci}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cistatic void
147062306a36Sopenharmony_cin_tty_receive_char_flagged(struct tty_struct *tty, u8 c, u8 flag)
147162306a36Sopenharmony_ci{
147262306a36Sopenharmony_ci	switch (flag) {
147362306a36Sopenharmony_ci	case TTY_BREAK:
147462306a36Sopenharmony_ci		n_tty_receive_break(tty);
147562306a36Sopenharmony_ci		break;
147662306a36Sopenharmony_ci	case TTY_PARITY:
147762306a36Sopenharmony_ci	case TTY_FRAME:
147862306a36Sopenharmony_ci		n_tty_receive_parity_error(tty, c);
147962306a36Sopenharmony_ci		break;
148062306a36Sopenharmony_ci	case TTY_OVERRUN:
148162306a36Sopenharmony_ci		n_tty_receive_overrun(tty);
148262306a36Sopenharmony_ci		break;
148362306a36Sopenharmony_ci	default:
148462306a36Sopenharmony_ci		tty_err(tty, "unknown flag %u\n", flag);
148562306a36Sopenharmony_ci		break;
148662306a36Sopenharmony_ci	}
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_cistatic void
149062306a36Sopenharmony_cin_tty_receive_char_lnext(struct tty_struct *tty, u8 c, u8 flag)
149162306a36Sopenharmony_ci{
149262306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	ldata->lnext = 0;
149562306a36Sopenharmony_ci	if (likely(flag == TTY_NORMAL)) {
149662306a36Sopenharmony_ci		if (I_ISTRIP(tty))
149762306a36Sopenharmony_ci			c &= 0x7f;
149862306a36Sopenharmony_ci		if (I_IUCLC(tty) && L_IEXTEN(tty))
149962306a36Sopenharmony_ci			c = tolower(c);
150062306a36Sopenharmony_ci		n_tty_receive_char(tty, c);
150162306a36Sopenharmony_ci	} else
150262306a36Sopenharmony_ci		n_tty_receive_char_flagged(tty, c, flag);
150362306a36Sopenharmony_ci}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci/* Caller must ensure count > 0 */
150662306a36Sopenharmony_cistatic void n_tty_lookahead_flow_ctrl(struct tty_struct *tty, const u8 *cp,
150762306a36Sopenharmony_ci				      const u8 *fp, size_t count)
150862306a36Sopenharmony_ci{
150962306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
151062306a36Sopenharmony_ci	u8 flag = TTY_NORMAL;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	ldata->lookahead_count += count;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	if (!I_IXON(tty))
151562306a36Sopenharmony_ci		return;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	while (count--) {
151862306a36Sopenharmony_ci		if (fp)
151962306a36Sopenharmony_ci			flag = *fp++;
152062306a36Sopenharmony_ci		if (likely(flag == TTY_NORMAL))
152162306a36Sopenharmony_ci			n_tty_receive_char_flow_ctrl(tty, *cp, false);
152262306a36Sopenharmony_ci		cp++;
152362306a36Sopenharmony_ci	}
152462306a36Sopenharmony_ci}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cistatic void
152762306a36Sopenharmony_cin_tty_receive_buf_real_raw(const struct tty_struct *tty, const u8 *cp,
152862306a36Sopenharmony_ci			   size_t count)
152962306a36Sopenharmony_ci{
153062306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	/* handle buffer wrap-around by a loop */
153362306a36Sopenharmony_ci	for (unsigned int i = 0; i < 2; i++) {
153462306a36Sopenharmony_ci		size_t head = MASK(ldata->read_head);
153562306a36Sopenharmony_ci		size_t n = min(count, N_TTY_BUF_SIZE - head);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci		memcpy(read_buf_addr(ldata, head), cp, n);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci		ldata->read_head += n;
154062306a36Sopenharmony_ci		cp += n;
154162306a36Sopenharmony_ci		count -= n;
154262306a36Sopenharmony_ci	}
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_cistatic void
154662306a36Sopenharmony_cin_tty_receive_buf_raw(struct tty_struct *tty, const u8 *cp, const u8 *fp,
154762306a36Sopenharmony_ci		      size_t count)
154862306a36Sopenharmony_ci{
154962306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
155062306a36Sopenharmony_ci	u8 flag = TTY_NORMAL;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	while (count--) {
155362306a36Sopenharmony_ci		if (fp)
155462306a36Sopenharmony_ci			flag = *fp++;
155562306a36Sopenharmony_ci		if (likely(flag == TTY_NORMAL))
155662306a36Sopenharmony_ci			put_tty_queue(*cp++, ldata);
155762306a36Sopenharmony_ci		else
155862306a36Sopenharmony_ci			n_tty_receive_char_flagged(tty, *cp++, flag);
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_cistatic void
156362306a36Sopenharmony_cin_tty_receive_buf_closing(struct tty_struct *tty, const u8 *cp, const u8 *fp,
156462306a36Sopenharmony_ci			  size_t count, bool lookahead_done)
156562306a36Sopenharmony_ci{
156662306a36Sopenharmony_ci	u8 flag = TTY_NORMAL;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	while (count--) {
156962306a36Sopenharmony_ci		if (fp)
157062306a36Sopenharmony_ci			flag = *fp++;
157162306a36Sopenharmony_ci		if (likely(flag == TTY_NORMAL))
157262306a36Sopenharmony_ci			n_tty_receive_char_closing(tty, *cp++, lookahead_done);
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_cistatic void n_tty_receive_buf_standard(struct tty_struct *tty, const u8 *cp,
157762306a36Sopenharmony_ci				       const u8 *fp, size_t count,
157862306a36Sopenharmony_ci				       bool lookahead_done)
157962306a36Sopenharmony_ci{
158062306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
158162306a36Sopenharmony_ci	u8 flag = TTY_NORMAL;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	while (count--) {
158462306a36Sopenharmony_ci		u8 c = *cp++;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci		if (fp)
158762306a36Sopenharmony_ci			flag = *fp++;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci		if (ldata->lnext) {
159062306a36Sopenharmony_ci			n_tty_receive_char_lnext(tty, c, flag);
159162306a36Sopenharmony_ci			continue;
159262306a36Sopenharmony_ci		}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci		if (unlikely(flag != TTY_NORMAL)) {
159562306a36Sopenharmony_ci			n_tty_receive_char_flagged(tty, c, flag);
159662306a36Sopenharmony_ci			continue;
159762306a36Sopenharmony_ci		}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci		if (I_ISTRIP(tty))
160062306a36Sopenharmony_ci			c &= 0x7f;
160162306a36Sopenharmony_ci		if (I_IUCLC(tty) && L_IEXTEN(tty))
160262306a36Sopenharmony_ci			c = tolower(c);
160362306a36Sopenharmony_ci		if (L_EXTPROC(tty)) {
160462306a36Sopenharmony_ci			put_tty_queue(c, ldata);
160562306a36Sopenharmony_ci			continue;
160662306a36Sopenharmony_ci		}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci		if (test_bit(c, ldata->char_map))
160962306a36Sopenharmony_ci			n_tty_receive_char_special(tty, c, lookahead_done);
161062306a36Sopenharmony_ci		else
161162306a36Sopenharmony_ci			n_tty_receive_char(tty, c);
161262306a36Sopenharmony_ci	}
161362306a36Sopenharmony_ci}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_cistatic void __receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp,
161662306a36Sopenharmony_ci			  size_t count)
161762306a36Sopenharmony_ci{
161862306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
161962306a36Sopenharmony_ci	bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
162062306a36Sopenharmony_ci	size_t la_count = min(ldata->lookahead_count, count);
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	if (ldata->real_raw)
162362306a36Sopenharmony_ci		n_tty_receive_buf_real_raw(tty, cp, count);
162462306a36Sopenharmony_ci	else if (ldata->raw || (L_EXTPROC(tty) && !preops))
162562306a36Sopenharmony_ci		n_tty_receive_buf_raw(tty, cp, fp, count);
162662306a36Sopenharmony_ci	else if (tty->closing && !L_EXTPROC(tty)) {
162762306a36Sopenharmony_ci		if (la_count > 0)
162862306a36Sopenharmony_ci			n_tty_receive_buf_closing(tty, cp, fp, la_count, true);
162962306a36Sopenharmony_ci		if (count > la_count)
163062306a36Sopenharmony_ci			n_tty_receive_buf_closing(tty, cp, fp, count - la_count, false);
163162306a36Sopenharmony_ci	} else {
163262306a36Sopenharmony_ci		if (la_count > 0)
163362306a36Sopenharmony_ci			n_tty_receive_buf_standard(tty, cp, fp, la_count, true);
163462306a36Sopenharmony_ci		if (count > la_count)
163562306a36Sopenharmony_ci			n_tty_receive_buf_standard(tty, cp, fp, count - la_count, false);
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci		flush_echoes(tty);
163862306a36Sopenharmony_ci		if (tty->ops->flush_chars)
163962306a36Sopenharmony_ci			tty->ops->flush_chars(tty);
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	ldata->lookahead_count -= la_count;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	if (ldata->icanon && !L_EXTPROC(tty))
164562306a36Sopenharmony_ci		return;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	/* publish read_head to consumer */
164862306a36Sopenharmony_ci	smp_store_release(&ldata->commit_head, ldata->read_head);
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	if (read_cnt(ldata)) {
165162306a36Sopenharmony_ci		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
165262306a36Sopenharmony_ci		wake_up_interruptible_poll(&tty->read_wait, EPOLLIN | EPOLLRDNORM);
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci/**
165762306a36Sopenharmony_ci * n_tty_receive_buf_common	-	process input
165862306a36Sopenharmony_ci * @tty: device to receive input
165962306a36Sopenharmony_ci * @cp: input chars
166062306a36Sopenharmony_ci * @fp: flags for each char (if %NULL, all chars are %TTY_NORMAL)
166162306a36Sopenharmony_ci * @count: number of input chars in @cp
166262306a36Sopenharmony_ci * @flow: enable flow control
166362306a36Sopenharmony_ci *
166462306a36Sopenharmony_ci * Called by the terminal driver when a block of characters has been received.
166562306a36Sopenharmony_ci * This function must be called from soft contexts not from interrupt context.
166662306a36Sopenharmony_ci * The driver is responsible for making calls one at a time and in order (or
166762306a36Sopenharmony_ci * using flush_to_ldisc()).
166862306a36Sopenharmony_ci *
166962306a36Sopenharmony_ci * Returns: the # of input chars from @cp which were processed.
167062306a36Sopenharmony_ci *
167162306a36Sopenharmony_ci * In canonical mode, the maximum line length is 4096 chars (including the line
167262306a36Sopenharmony_ci * termination char); lines longer than 4096 chars are truncated. After 4095
167362306a36Sopenharmony_ci * chars, input data is still processed but not stored. Overflow processing
167462306a36Sopenharmony_ci * ensures the tty can always receive more input until at least one line can be
167562306a36Sopenharmony_ci * read.
167662306a36Sopenharmony_ci *
167762306a36Sopenharmony_ci * In non-canonical mode, the read buffer will only accept 4095 chars; this
167862306a36Sopenharmony_ci * provides the necessary space for a newline char if the input mode is
167962306a36Sopenharmony_ci * switched to canonical.
168062306a36Sopenharmony_ci *
168162306a36Sopenharmony_ci * Note it is possible for the read buffer to _contain_ 4096 chars in
168262306a36Sopenharmony_ci * non-canonical mode: the read buffer could already contain the maximum canon
168362306a36Sopenharmony_ci * line of 4096 chars when the mode is switched to non-canonical.
168462306a36Sopenharmony_ci *
168562306a36Sopenharmony_ci * Locking: n_tty_receive_buf()/producer path:
168662306a36Sopenharmony_ci *	claims non-exclusive %termios_rwsem
168762306a36Sopenharmony_ci *	publishes commit_head or canon_head
168862306a36Sopenharmony_ci */
168962306a36Sopenharmony_cistatic size_t
169062306a36Sopenharmony_cin_tty_receive_buf_common(struct tty_struct *tty, const u8 *cp, const u8 *fp,
169162306a36Sopenharmony_ci			 size_t count, bool flow)
169262306a36Sopenharmony_ci{
169362306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
169462306a36Sopenharmony_ci	size_t n, rcvd = 0;
169562306a36Sopenharmony_ci	int room, overflow;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	down_read(&tty->termios_rwsem);
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	do {
170062306a36Sopenharmony_ci		/*
170162306a36Sopenharmony_ci		 * When PARMRK is set, each input char may take up to 3 chars
170262306a36Sopenharmony_ci		 * in the read buf; reduce the buffer space avail by 3x
170362306a36Sopenharmony_ci		 *
170462306a36Sopenharmony_ci		 * If we are doing input canonicalization, and there are no
170562306a36Sopenharmony_ci		 * pending newlines, let characters through without limit, so
170662306a36Sopenharmony_ci		 * that erase characters will be handled.  Other excess
170762306a36Sopenharmony_ci		 * characters will be beeped.
170862306a36Sopenharmony_ci		 *
170962306a36Sopenharmony_ci		 * paired with store in *_copy_from_read_buf() -- guarantees
171062306a36Sopenharmony_ci		 * the consumer has loaded the data in read_buf up to the new
171162306a36Sopenharmony_ci		 * read_tail (so this producer will not overwrite unread data)
171262306a36Sopenharmony_ci		 */
171362306a36Sopenharmony_ci		size_t tail = smp_load_acquire(&ldata->read_tail);
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci		room = N_TTY_BUF_SIZE - (ldata->read_head - tail);
171662306a36Sopenharmony_ci		if (I_PARMRK(tty))
171762306a36Sopenharmony_ci			room = DIV_ROUND_UP(room, 3);
171862306a36Sopenharmony_ci		room--;
171962306a36Sopenharmony_ci		if (room <= 0) {
172062306a36Sopenharmony_ci			overflow = ldata->icanon && ldata->canon_head == tail;
172162306a36Sopenharmony_ci			if (overflow && room < 0)
172262306a36Sopenharmony_ci				ldata->read_head--;
172362306a36Sopenharmony_ci			room = overflow;
172462306a36Sopenharmony_ci			WRITE_ONCE(ldata->no_room, flow && !room);
172562306a36Sopenharmony_ci		} else
172662306a36Sopenharmony_ci			overflow = 0;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci		n = min_t(size_t, count, room);
172962306a36Sopenharmony_ci		if (!n)
173062306a36Sopenharmony_ci			break;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci		/* ignore parity errors if handling overflow */
173362306a36Sopenharmony_ci		if (!overflow || !fp || *fp != TTY_PARITY)
173462306a36Sopenharmony_ci			__receive_buf(tty, cp, fp, n);
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci		cp += n;
173762306a36Sopenharmony_ci		if (fp)
173862306a36Sopenharmony_ci			fp += n;
173962306a36Sopenharmony_ci		count -= n;
174062306a36Sopenharmony_ci		rcvd += n;
174162306a36Sopenharmony_ci	} while (!test_bit(TTY_LDISC_CHANGING, &tty->flags));
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	tty->receive_room = room;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	/* Unthrottle if handling overflow on pty */
174662306a36Sopenharmony_ci	if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
174762306a36Sopenharmony_ci		if (overflow) {
174862306a36Sopenharmony_ci			tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
174962306a36Sopenharmony_ci			tty_unthrottle_safe(tty);
175062306a36Sopenharmony_ci			__tty_set_flow_change(tty, 0);
175162306a36Sopenharmony_ci		}
175262306a36Sopenharmony_ci	} else
175362306a36Sopenharmony_ci		n_tty_check_throttle(tty);
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	if (unlikely(ldata->no_room)) {
175662306a36Sopenharmony_ci		/*
175762306a36Sopenharmony_ci		 * Barrier here is to ensure to read the latest read_tail in
175862306a36Sopenharmony_ci		 * chars_in_buffer() and to make sure that read_tail is not loaded
175962306a36Sopenharmony_ci		 * before ldata->no_room is set.
176062306a36Sopenharmony_ci		 */
176162306a36Sopenharmony_ci		smp_mb();
176262306a36Sopenharmony_ci		if (!chars_in_buffer(tty))
176362306a36Sopenharmony_ci			n_tty_kick_worker(tty);
176462306a36Sopenharmony_ci	}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	up_read(&tty->termios_rwsem);
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	return rcvd;
176962306a36Sopenharmony_ci}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_cistatic void n_tty_receive_buf(struct tty_struct *tty, const u8 *cp,
177262306a36Sopenharmony_ci			      const u8 *fp, size_t count)
177362306a36Sopenharmony_ci{
177462306a36Sopenharmony_ci	n_tty_receive_buf_common(tty, cp, fp, count, false);
177562306a36Sopenharmony_ci}
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_cistatic size_t n_tty_receive_buf2(struct tty_struct *tty, const u8 *cp,
177862306a36Sopenharmony_ci				 const u8 *fp, size_t count)
177962306a36Sopenharmony_ci{
178062306a36Sopenharmony_ci	return n_tty_receive_buf_common(tty, cp, fp, count, true);
178162306a36Sopenharmony_ci}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci/**
178462306a36Sopenharmony_ci * n_tty_set_termios	-	termios data changed
178562306a36Sopenharmony_ci * @tty: terminal
178662306a36Sopenharmony_ci * @old: previous data
178762306a36Sopenharmony_ci *
178862306a36Sopenharmony_ci * Called by the tty layer when the user changes termios flags so that the line
178962306a36Sopenharmony_ci * discipline can plan ahead. This function cannot sleep and is protected from
179062306a36Sopenharmony_ci * re-entry by the tty layer. The user is guaranteed that this function will
179162306a36Sopenharmony_ci * not be re-entered or in progress when the ldisc is closed.
179262306a36Sopenharmony_ci *
179362306a36Sopenharmony_ci * Locking: Caller holds @tty->termios_rwsem
179462306a36Sopenharmony_ci */
179562306a36Sopenharmony_cistatic void n_tty_set_termios(struct tty_struct *tty, const struct ktermios *old)
179662306a36Sopenharmony_ci{
179762306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	if (!old || (old->c_lflag ^ tty->termios.c_lflag) & (ICANON | EXTPROC)) {
180062306a36Sopenharmony_ci		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
180162306a36Sopenharmony_ci		ldata->line_start = ldata->read_tail;
180262306a36Sopenharmony_ci		if (!L_ICANON(tty) || !read_cnt(ldata)) {
180362306a36Sopenharmony_ci			ldata->canon_head = ldata->read_tail;
180462306a36Sopenharmony_ci			ldata->push = 0;
180562306a36Sopenharmony_ci		} else {
180662306a36Sopenharmony_ci			set_bit(MASK(ldata->read_head - 1), ldata->read_flags);
180762306a36Sopenharmony_ci			ldata->canon_head = ldata->read_head;
180862306a36Sopenharmony_ci			ldata->push = 1;
180962306a36Sopenharmony_ci		}
181062306a36Sopenharmony_ci		ldata->commit_head = ldata->read_head;
181162306a36Sopenharmony_ci		ldata->erasing = 0;
181262306a36Sopenharmony_ci		ldata->lnext = 0;
181362306a36Sopenharmony_ci	}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	ldata->icanon = (L_ICANON(tty) != 0);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
181862306a36Sopenharmony_ci	    I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
181962306a36Sopenharmony_ci	    I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
182062306a36Sopenharmony_ci	    I_PARMRK(tty)) {
182162306a36Sopenharmony_ci		bitmap_zero(ldata->char_map, 256);
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci		if (I_IGNCR(tty) || I_ICRNL(tty))
182462306a36Sopenharmony_ci			set_bit('\r', ldata->char_map);
182562306a36Sopenharmony_ci		if (I_INLCR(tty))
182662306a36Sopenharmony_ci			set_bit('\n', ldata->char_map);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci		if (L_ICANON(tty)) {
182962306a36Sopenharmony_ci			set_bit(ERASE_CHAR(tty), ldata->char_map);
183062306a36Sopenharmony_ci			set_bit(KILL_CHAR(tty), ldata->char_map);
183162306a36Sopenharmony_ci			set_bit(EOF_CHAR(tty), ldata->char_map);
183262306a36Sopenharmony_ci			set_bit('\n', ldata->char_map);
183362306a36Sopenharmony_ci			set_bit(EOL_CHAR(tty), ldata->char_map);
183462306a36Sopenharmony_ci			if (L_IEXTEN(tty)) {
183562306a36Sopenharmony_ci				set_bit(WERASE_CHAR(tty), ldata->char_map);
183662306a36Sopenharmony_ci				set_bit(LNEXT_CHAR(tty), ldata->char_map);
183762306a36Sopenharmony_ci				set_bit(EOL2_CHAR(tty), ldata->char_map);
183862306a36Sopenharmony_ci				if (L_ECHO(tty))
183962306a36Sopenharmony_ci					set_bit(REPRINT_CHAR(tty),
184062306a36Sopenharmony_ci						ldata->char_map);
184162306a36Sopenharmony_ci			}
184262306a36Sopenharmony_ci		}
184362306a36Sopenharmony_ci		if (I_IXON(tty)) {
184462306a36Sopenharmony_ci			set_bit(START_CHAR(tty), ldata->char_map);
184562306a36Sopenharmony_ci			set_bit(STOP_CHAR(tty), ldata->char_map);
184662306a36Sopenharmony_ci		}
184762306a36Sopenharmony_ci		if (L_ISIG(tty)) {
184862306a36Sopenharmony_ci			set_bit(INTR_CHAR(tty), ldata->char_map);
184962306a36Sopenharmony_ci			set_bit(QUIT_CHAR(tty), ldata->char_map);
185062306a36Sopenharmony_ci			set_bit(SUSP_CHAR(tty), ldata->char_map);
185162306a36Sopenharmony_ci		}
185262306a36Sopenharmony_ci		clear_bit(__DISABLED_CHAR, ldata->char_map);
185362306a36Sopenharmony_ci		ldata->raw = 0;
185462306a36Sopenharmony_ci		ldata->real_raw = 0;
185562306a36Sopenharmony_ci	} else {
185662306a36Sopenharmony_ci		ldata->raw = 1;
185762306a36Sopenharmony_ci		if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
185862306a36Sopenharmony_ci		    (I_IGNPAR(tty) || !I_INPCK(tty)) &&
185962306a36Sopenharmony_ci		    (tty->driver->flags & TTY_DRIVER_REAL_RAW))
186062306a36Sopenharmony_ci			ldata->real_raw = 1;
186162306a36Sopenharmony_ci		else
186262306a36Sopenharmony_ci			ldata->real_raw = 0;
186362306a36Sopenharmony_ci	}
186462306a36Sopenharmony_ci	/*
186562306a36Sopenharmony_ci	 * Fix tty hang when I_IXON(tty) is cleared, but the tty
186662306a36Sopenharmony_ci	 * been stopped by STOP_CHAR(tty) before it.
186762306a36Sopenharmony_ci	 */
186862306a36Sopenharmony_ci	if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow.tco_stopped) {
186962306a36Sopenharmony_ci		start_tty(tty);
187062306a36Sopenharmony_ci		process_echoes(tty);
187162306a36Sopenharmony_ci	}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	/* The termios change make the tty ready for I/O */
187462306a36Sopenharmony_ci	wake_up_interruptible(&tty->write_wait);
187562306a36Sopenharmony_ci	wake_up_interruptible(&tty->read_wait);
187662306a36Sopenharmony_ci}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci/**
187962306a36Sopenharmony_ci * n_tty_close		-	close the ldisc for this tty
188062306a36Sopenharmony_ci * @tty: device
188162306a36Sopenharmony_ci *
188262306a36Sopenharmony_ci * Called from the terminal layer when this line discipline is being shut down,
188362306a36Sopenharmony_ci * either because of a close or becsuse of a discipline change. The function
188462306a36Sopenharmony_ci * will not be called while other ldisc methods are in progress.
188562306a36Sopenharmony_ci */
188662306a36Sopenharmony_cistatic void n_tty_close(struct tty_struct *tty)
188762306a36Sopenharmony_ci{
188862306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	if (tty->link)
189162306a36Sopenharmony_ci		n_tty_packet_mode_flush(tty);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	down_write(&tty->termios_rwsem);
189462306a36Sopenharmony_ci	vfree(ldata);
189562306a36Sopenharmony_ci	tty->disc_data = NULL;
189662306a36Sopenharmony_ci	up_write(&tty->termios_rwsem);
189762306a36Sopenharmony_ci}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci/**
190062306a36Sopenharmony_ci * n_tty_open		-	open an ldisc
190162306a36Sopenharmony_ci * @tty: terminal to open
190262306a36Sopenharmony_ci *
190362306a36Sopenharmony_ci * Called when this line discipline is being attached to the terminal device.
190462306a36Sopenharmony_ci * Can sleep. Called serialized so that no other events will occur in parallel.
190562306a36Sopenharmony_ci * No further open will occur until a close.
190662306a36Sopenharmony_ci */
190762306a36Sopenharmony_cistatic int n_tty_open(struct tty_struct *tty)
190862306a36Sopenharmony_ci{
190962306a36Sopenharmony_ci	struct n_tty_data *ldata;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	/* Currently a malloc failure here can panic */
191262306a36Sopenharmony_ci	ldata = vzalloc(sizeof(*ldata));
191362306a36Sopenharmony_ci	if (!ldata)
191462306a36Sopenharmony_ci		return -ENOMEM;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	ldata->overrun_time = jiffies;
191762306a36Sopenharmony_ci	mutex_init(&ldata->atomic_read_lock);
191862306a36Sopenharmony_ci	mutex_init(&ldata->output_lock);
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	tty->disc_data = ldata;
192162306a36Sopenharmony_ci	tty->closing = 0;
192262306a36Sopenharmony_ci	/* indicate buffer work may resume */
192362306a36Sopenharmony_ci	clear_bit(TTY_LDISC_HALTED, &tty->flags);
192462306a36Sopenharmony_ci	n_tty_set_termios(tty, NULL);
192562306a36Sopenharmony_ci	tty_unthrottle(tty);
192662306a36Sopenharmony_ci	return 0;
192762306a36Sopenharmony_ci}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_cistatic inline int input_available_p(const struct tty_struct *tty, int poll)
193062306a36Sopenharmony_ci{
193162306a36Sopenharmony_ci	const struct n_tty_data *ldata = tty->disc_data;
193262306a36Sopenharmony_ci	int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	if (ldata->icanon && !L_EXTPROC(tty))
193562306a36Sopenharmony_ci		return ldata->canon_head != ldata->read_tail;
193662306a36Sopenharmony_ci	else
193762306a36Sopenharmony_ci		return ldata->commit_head - ldata->read_tail >= amt;
193862306a36Sopenharmony_ci}
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci/**
194162306a36Sopenharmony_ci * copy_from_read_buf	-	copy read data directly
194262306a36Sopenharmony_ci * @tty: terminal device
194362306a36Sopenharmony_ci * @kbp: data
194462306a36Sopenharmony_ci * @nr: size of data
194562306a36Sopenharmony_ci *
194662306a36Sopenharmony_ci * Helper function to speed up n_tty_read(). It is only called when %ICANON is
194762306a36Sopenharmony_ci * off; it copies characters straight from the tty queue.
194862306a36Sopenharmony_ci *
194962306a36Sopenharmony_ci * Returns: true if it successfully copied data, but there is still more data
195062306a36Sopenharmony_ci * to be had.
195162306a36Sopenharmony_ci *
195262306a36Sopenharmony_ci * Locking:
195362306a36Sopenharmony_ci *  * called under the @ldata->atomic_read_lock sem
195462306a36Sopenharmony_ci *  * n_tty_read()/consumer path:
195562306a36Sopenharmony_ci *		caller holds non-exclusive %termios_rwsem;
195662306a36Sopenharmony_ci *		read_tail published
195762306a36Sopenharmony_ci */
195862306a36Sopenharmony_cistatic bool copy_from_read_buf(const struct tty_struct *tty, u8 **kbp,
195962306a36Sopenharmony_ci			       size_t *nr)
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci{
196262306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
196362306a36Sopenharmony_ci	size_t n;
196462306a36Sopenharmony_ci	bool is_eof;
196562306a36Sopenharmony_ci	size_t head = smp_load_acquire(&ldata->commit_head);
196662306a36Sopenharmony_ci	size_t tail = MASK(ldata->read_tail);
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
196962306a36Sopenharmony_ci	n = min(*nr, n);
197062306a36Sopenharmony_ci	if (n) {
197162306a36Sopenharmony_ci		u8 *from = read_buf_addr(ldata, tail);
197262306a36Sopenharmony_ci		memcpy(*kbp, from, n);
197362306a36Sopenharmony_ci		is_eof = n == 1 && *from == EOF_CHAR(tty);
197462306a36Sopenharmony_ci		tty_audit_add_data(tty, from, n);
197562306a36Sopenharmony_ci		zero_buffer(tty, from, n);
197662306a36Sopenharmony_ci		smp_store_release(&ldata->read_tail, ldata->read_tail + n);
197762306a36Sopenharmony_ci		/* Turn single EOF into zero-length read */
197862306a36Sopenharmony_ci		if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
197962306a36Sopenharmony_ci		    (head == ldata->read_tail))
198062306a36Sopenharmony_ci			return false;
198162306a36Sopenharmony_ci		*kbp += n;
198262306a36Sopenharmony_ci		*nr -= n;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci		/* If we have more to copy, let the caller know */
198562306a36Sopenharmony_ci		return head != ldata->read_tail;
198662306a36Sopenharmony_ci	}
198762306a36Sopenharmony_ci	return false;
198862306a36Sopenharmony_ci}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci/**
199162306a36Sopenharmony_ci * canon_copy_from_read_buf	-	copy read data in canonical mode
199262306a36Sopenharmony_ci * @tty: terminal device
199362306a36Sopenharmony_ci * @kbp: data
199462306a36Sopenharmony_ci * @nr: size of data
199562306a36Sopenharmony_ci *
199662306a36Sopenharmony_ci * Helper function for n_tty_read(). It is only called when %ICANON is on; it
199762306a36Sopenharmony_ci * copies one line of input up to and including the line-delimiting character
199862306a36Sopenharmony_ci * into the result buffer.
199962306a36Sopenharmony_ci *
200062306a36Sopenharmony_ci * Note: When termios is changed from non-canonical to canonical mode and the
200162306a36Sopenharmony_ci * read buffer contains data, n_tty_set_termios() simulates an EOF push (as if
200262306a36Sopenharmony_ci * C-d were input) _without_ the %DISABLED_CHAR in the buffer. This causes data
200362306a36Sopenharmony_ci * already processed as input to be immediately available as input although a
200462306a36Sopenharmony_ci * newline has not been received.
200562306a36Sopenharmony_ci *
200662306a36Sopenharmony_ci * Locking:
200762306a36Sopenharmony_ci *  * called under the %atomic_read_lock mutex
200862306a36Sopenharmony_ci *  * n_tty_read()/consumer path:
200962306a36Sopenharmony_ci *	caller holds non-exclusive %termios_rwsem;
201062306a36Sopenharmony_ci *	read_tail published
201162306a36Sopenharmony_ci */
201262306a36Sopenharmony_cistatic bool canon_copy_from_read_buf(const struct tty_struct *tty, u8 **kbp,
201362306a36Sopenharmony_ci				     size_t *nr)
201462306a36Sopenharmony_ci{
201562306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
201662306a36Sopenharmony_ci	size_t n, size, more, c;
201762306a36Sopenharmony_ci	size_t eol;
201862306a36Sopenharmony_ci	size_t tail, canon_head;
201962306a36Sopenharmony_ci	int found = 0;
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	/* N.B. avoid overrun if nr == 0 */
202262306a36Sopenharmony_ci	if (!*nr)
202362306a36Sopenharmony_ci		return false;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	canon_head = smp_load_acquire(&ldata->canon_head);
202662306a36Sopenharmony_ci	n = min(*nr, canon_head - ldata->read_tail);
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	tail = MASK(ldata->read_tail);
202962306a36Sopenharmony_ci	size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu\n",
203262306a36Sopenharmony_ci		    __func__, *nr, tail, n, size);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	eol = find_next_bit(ldata->read_flags, size, tail);
203562306a36Sopenharmony_ci	more = n - (size - tail);
203662306a36Sopenharmony_ci	if (eol == N_TTY_BUF_SIZE && more) {
203762306a36Sopenharmony_ci		/* scan wrapped without finding set bit */
203862306a36Sopenharmony_ci		eol = find_first_bit(ldata->read_flags, more);
203962306a36Sopenharmony_ci		found = eol != more;
204062306a36Sopenharmony_ci	} else
204162306a36Sopenharmony_ci		found = eol != size;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	n = eol - tail;
204462306a36Sopenharmony_ci	if (n > N_TTY_BUF_SIZE)
204562306a36Sopenharmony_ci		n += N_TTY_BUF_SIZE;
204662306a36Sopenharmony_ci	c = n + found;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	if (!found || read_buf(ldata, eol) != __DISABLED_CHAR)
204962306a36Sopenharmony_ci		n = c;
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n",
205262306a36Sopenharmony_ci		    __func__, eol, found, n, c, tail, more);
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	tty_copy(tty, *kbp, tail, n);
205562306a36Sopenharmony_ci	*kbp += n;
205662306a36Sopenharmony_ci	*nr -= n;
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	if (found)
205962306a36Sopenharmony_ci		clear_bit(eol, ldata->read_flags);
206062306a36Sopenharmony_ci	smp_store_release(&ldata->read_tail, ldata->read_tail + c);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	if (found) {
206362306a36Sopenharmony_ci		if (!ldata->push)
206462306a36Sopenharmony_ci			ldata->line_start = ldata->read_tail;
206562306a36Sopenharmony_ci		else
206662306a36Sopenharmony_ci			ldata->push = 0;
206762306a36Sopenharmony_ci		tty_audit_push();
206862306a36Sopenharmony_ci		return false;
206962306a36Sopenharmony_ci	}
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	/* No EOL found - do a continuation retry if there is more data */
207262306a36Sopenharmony_ci	return ldata->read_tail != canon_head;
207362306a36Sopenharmony_ci}
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci/*
207662306a36Sopenharmony_ci * If we finished a read at the exact location of an
207762306a36Sopenharmony_ci * EOF (special EOL character that's a __DISABLED_CHAR)
207862306a36Sopenharmony_ci * in the stream, silently eat the EOF.
207962306a36Sopenharmony_ci */
208062306a36Sopenharmony_cistatic void canon_skip_eof(struct n_tty_data *ldata)
208162306a36Sopenharmony_ci{
208262306a36Sopenharmony_ci	size_t tail, canon_head;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	canon_head = smp_load_acquire(&ldata->canon_head);
208562306a36Sopenharmony_ci	tail = ldata->read_tail;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	// No data?
208862306a36Sopenharmony_ci	if (tail == canon_head)
208962306a36Sopenharmony_ci		return;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	// See if the tail position is EOF in the circular buffer
209262306a36Sopenharmony_ci	tail &= (N_TTY_BUF_SIZE - 1);
209362306a36Sopenharmony_ci	if (!test_bit(tail, ldata->read_flags))
209462306a36Sopenharmony_ci		return;
209562306a36Sopenharmony_ci	if (read_buf(ldata, tail) != __DISABLED_CHAR)
209662306a36Sopenharmony_ci		return;
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	// Clear the EOL bit, skip the EOF char.
209962306a36Sopenharmony_ci	clear_bit(tail, ldata->read_flags);
210062306a36Sopenharmony_ci	smp_store_release(&ldata->read_tail, ldata->read_tail + 1);
210162306a36Sopenharmony_ci}
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci/**
210462306a36Sopenharmony_ci * job_control		-	check job control
210562306a36Sopenharmony_ci * @tty: tty
210662306a36Sopenharmony_ci * @file: file handle
210762306a36Sopenharmony_ci *
210862306a36Sopenharmony_ci * Perform job control management checks on this @file/@tty descriptor and if
210962306a36Sopenharmony_ci * appropriate send any needed signals and return a negative error code if
211062306a36Sopenharmony_ci * action should be taken.
211162306a36Sopenharmony_ci *
211262306a36Sopenharmony_ci * Locking:
211362306a36Sopenharmony_ci *  * redirected write test is safe
211462306a36Sopenharmony_ci *  * current->signal->tty check is safe
211562306a36Sopenharmony_ci *  * ctrl.lock to safely reference @tty->ctrl.pgrp
211662306a36Sopenharmony_ci */
211762306a36Sopenharmony_cistatic int job_control(struct tty_struct *tty, struct file *file)
211862306a36Sopenharmony_ci{
211962306a36Sopenharmony_ci	/* Job control check -- must be done at start and after
212062306a36Sopenharmony_ci	   every sleep (POSIX.1 7.1.1.4). */
212162306a36Sopenharmony_ci	/* NOTE: not yet done after every sleep pending a thorough
212262306a36Sopenharmony_ci	   check of the logic of this change. -- jlc */
212362306a36Sopenharmony_ci	/* don't stop on /dev/console */
212462306a36Sopenharmony_ci	if (file->f_op->write_iter == redirected_tty_write)
212562306a36Sopenharmony_ci		return 0;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	return __tty_check_change(tty, SIGTTIN);
212862306a36Sopenharmony_ci}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci/**
213262306a36Sopenharmony_ci * n_tty_read		-	read function for tty
213362306a36Sopenharmony_ci * @tty: tty device
213462306a36Sopenharmony_ci * @file: file object
213562306a36Sopenharmony_ci * @kbuf: kernelspace buffer pointer
213662306a36Sopenharmony_ci * @nr: size of I/O
213762306a36Sopenharmony_ci * @cookie: if non-%NULL, this is a continuation read
213862306a36Sopenharmony_ci * @offset: where to continue reading from (unused in n_tty)
213962306a36Sopenharmony_ci *
214062306a36Sopenharmony_ci * Perform reads for the line discipline. We are guaranteed that the line
214162306a36Sopenharmony_ci * discipline will not be closed under us but we may get multiple parallel
214262306a36Sopenharmony_ci * readers and must handle this ourselves. We may also get a hangup. Always
214362306a36Sopenharmony_ci * called in user context, may sleep.
214462306a36Sopenharmony_ci *
214562306a36Sopenharmony_ci * This code must be sure never to sleep through a hangup.
214662306a36Sopenharmony_ci *
214762306a36Sopenharmony_ci * Locking: n_tty_read()/consumer path:
214862306a36Sopenharmony_ci *	claims non-exclusive termios_rwsem;
214962306a36Sopenharmony_ci *	publishes read_tail
215062306a36Sopenharmony_ci */
215162306a36Sopenharmony_cistatic ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
215262306a36Sopenharmony_ci			  size_t nr, void **cookie, unsigned long offset)
215362306a36Sopenharmony_ci{
215462306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
215562306a36Sopenharmony_ci	u8 *kb = kbuf;
215662306a36Sopenharmony_ci	DEFINE_WAIT_FUNC(wait, woken_wake_function);
215762306a36Sopenharmony_ci	int c;
215862306a36Sopenharmony_ci	int minimum, time;
215962306a36Sopenharmony_ci	ssize_t retval = 0;
216062306a36Sopenharmony_ci	long timeout;
216162306a36Sopenharmony_ci	bool packet;
216262306a36Sopenharmony_ci	size_t old_tail;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	/*
216562306a36Sopenharmony_ci	 * Is this a continuation of a read started earler?
216662306a36Sopenharmony_ci	 *
216762306a36Sopenharmony_ci	 * If so, we still hold the atomic_read_lock and the
216862306a36Sopenharmony_ci	 * termios_rwsem, and can just continue to copy data.
216962306a36Sopenharmony_ci	 */
217062306a36Sopenharmony_ci	if (*cookie) {
217162306a36Sopenharmony_ci		if (ldata->icanon && !L_EXTPROC(tty)) {
217262306a36Sopenharmony_ci			/*
217362306a36Sopenharmony_ci			 * If we have filled the user buffer, see
217462306a36Sopenharmony_ci			 * if we should skip an EOF character before
217562306a36Sopenharmony_ci			 * releasing the lock and returning done.
217662306a36Sopenharmony_ci			 */
217762306a36Sopenharmony_ci			if (!nr)
217862306a36Sopenharmony_ci				canon_skip_eof(ldata);
217962306a36Sopenharmony_ci			else if (canon_copy_from_read_buf(tty, &kb, &nr))
218062306a36Sopenharmony_ci				return kb - kbuf;
218162306a36Sopenharmony_ci		} else {
218262306a36Sopenharmony_ci			if (copy_from_read_buf(tty, &kb, &nr))
218362306a36Sopenharmony_ci				return kb - kbuf;
218462306a36Sopenharmony_ci		}
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci		/* No more data - release locks and stop retries */
218762306a36Sopenharmony_ci		n_tty_kick_worker(tty);
218862306a36Sopenharmony_ci		n_tty_check_unthrottle(tty);
218962306a36Sopenharmony_ci		up_read(&tty->termios_rwsem);
219062306a36Sopenharmony_ci		mutex_unlock(&ldata->atomic_read_lock);
219162306a36Sopenharmony_ci		*cookie = NULL;
219262306a36Sopenharmony_ci		return kb - kbuf;
219362306a36Sopenharmony_ci	}
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci	c = job_control(tty, file);
219662306a36Sopenharmony_ci	if (c < 0)
219762306a36Sopenharmony_ci		return c;
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	/*
220062306a36Sopenharmony_ci	 *	Internal serialization of reads.
220162306a36Sopenharmony_ci	 */
220262306a36Sopenharmony_ci	if (file->f_flags & O_NONBLOCK) {
220362306a36Sopenharmony_ci		if (!mutex_trylock(&ldata->atomic_read_lock))
220462306a36Sopenharmony_ci			return -EAGAIN;
220562306a36Sopenharmony_ci	} else {
220662306a36Sopenharmony_ci		if (mutex_lock_interruptible(&ldata->atomic_read_lock))
220762306a36Sopenharmony_ci			return -ERESTARTSYS;
220862306a36Sopenharmony_ci	}
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	down_read(&tty->termios_rwsem);
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	minimum = time = 0;
221362306a36Sopenharmony_ci	timeout = MAX_SCHEDULE_TIMEOUT;
221462306a36Sopenharmony_ci	if (!ldata->icanon) {
221562306a36Sopenharmony_ci		minimum = MIN_CHAR(tty);
221662306a36Sopenharmony_ci		if (minimum) {
221762306a36Sopenharmony_ci			time = (HZ / 10) * TIME_CHAR(tty);
221862306a36Sopenharmony_ci		} else {
221962306a36Sopenharmony_ci			timeout = (HZ / 10) * TIME_CHAR(tty);
222062306a36Sopenharmony_ci			minimum = 1;
222162306a36Sopenharmony_ci		}
222262306a36Sopenharmony_ci	}
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	packet = tty->ctrl.packet;
222562306a36Sopenharmony_ci	old_tail = ldata->read_tail;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	add_wait_queue(&tty->read_wait, &wait);
222862306a36Sopenharmony_ci	while (nr) {
222962306a36Sopenharmony_ci		/* First test for status change. */
223062306a36Sopenharmony_ci		if (packet && tty->link->ctrl.pktstatus) {
223162306a36Sopenharmony_ci			u8 cs;
223262306a36Sopenharmony_ci			if (kb != kbuf)
223362306a36Sopenharmony_ci				break;
223462306a36Sopenharmony_ci			spin_lock_irq(&tty->link->ctrl.lock);
223562306a36Sopenharmony_ci			cs = tty->link->ctrl.pktstatus;
223662306a36Sopenharmony_ci			tty->link->ctrl.pktstatus = 0;
223762306a36Sopenharmony_ci			spin_unlock_irq(&tty->link->ctrl.lock);
223862306a36Sopenharmony_ci			*kb++ = cs;
223962306a36Sopenharmony_ci			nr--;
224062306a36Sopenharmony_ci			break;
224162306a36Sopenharmony_ci		}
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci		if (!input_available_p(tty, 0)) {
224462306a36Sopenharmony_ci			up_read(&tty->termios_rwsem);
224562306a36Sopenharmony_ci			tty_buffer_flush_work(tty->port);
224662306a36Sopenharmony_ci			down_read(&tty->termios_rwsem);
224762306a36Sopenharmony_ci			if (!input_available_p(tty, 0)) {
224862306a36Sopenharmony_ci				if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
224962306a36Sopenharmony_ci					retval = -EIO;
225062306a36Sopenharmony_ci					break;
225162306a36Sopenharmony_ci				}
225262306a36Sopenharmony_ci				if (tty_hung_up_p(file))
225362306a36Sopenharmony_ci					break;
225462306a36Sopenharmony_ci				/*
225562306a36Sopenharmony_ci				 * Abort readers for ttys which never actually
225662306a36Sopenharmony_ci				 * get hung up.  See __tty_hangup().
225762306a36Sopenharmony_ci				 */
225862306a36Sopenharmony_ci				if (test_bit(TTY_HUPPING, &tty->flags))
225962306a36Sopenharmony_ci					break;
226062306a36Sopenharmony_ci				if (!timeout)
226162306a36Sopenharmony_ci					break;
226262306a36Sopenharmony_ci				if (tty_io_nonblock(tty, file)) {
226362306a36Sopenharmony_ci					retval = -EAGAIN;
226462306a36Sopenharmony_ci					break;
226562306a36Sopenharmony_ci				}
226662306a36Sopenharmony_ci				if (signal_pending(current)) {
226762306a36Sopenharmony_ci					retval = -ERESTARTSYS;
226862306a36Sopenharmony_ci					break;
226962306a36Sopenharmony_ci				}
227062306a36Sopenharmony_ci				up_read(&tty->termios_rwsem);
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci				timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
227362306a36Sopenharmony_ci						timeout);
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci				down_read(&tty->termios_rwsem);
227662306a36Sopenharmony_ci				continue;
227762306a36Sopenharmony_ci			}
227862306a36Sopenharmony_ci		}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci		if (ldata->icanon && !L_EXTPROC(tty)) {
228162306a36Sopenharmony_ci			if (canon_copy_from_read_buf(tty, &kb, &nr))
228262306a36Sopenharmony_ci				goto more_to_be_read;
228362306a36Sopenharmony_ci		} else {
228462306a36Sopenharmony_ci			/* Deal with packet mode. */
228562306a36Sopenharmony_ci			if (packet && kb == kbuf) {
228662306a36Sopenharmony_ci				*kb++ = TIOCPKT_DATA;
228762306a36Sopenharmony_ci				nr--;
228862306a36Sopenharmony_ci			}
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci			/*
229162306a36Sopenharmony_ci			 * Copy data, and if there is more to be had
229262306a36Sopenharmony_ci			 * and we have nothing more to wait for, then
229362306a36Sopenharmony_ci			 * let's mark us for retries.
229462306a36Sopenharmony_ci			 *
229562306a36Sopenharmony_ci			 * NOTE! We return here with both the termios_sem
229662306a36Sopenharmony_ci			 * and atomic_read_lock still held, the retries
229762306a36Sopenharmony_ci			 * will release them when done.
229862306a36Sopenharmony_ci			 */
229962306a36Sopenharmony_ci			if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum) {
230062306a36Sopenharmony_cimore_to_be_read:
230162306a36Sopenharmony_ci				remove_wait_queue(&tty->read_wait, &wait);
230262306a36Sopenharmony_ci				*cookie = cookie;
230362306a36Sopenharmony_ci				return kb - kbuf;
230462306a36Sopenharmony_ci			}
230562306a36Sopenharmony_ci		}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci		n_tty_check_unthrottle(tty);
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci		if (kb - kbuf >= minimum)
231062306a36Sopenharmony_ci			break;
231162306a36Sopenharmony_ci		if (time)
231262306a36Sopenharmony_ci			timeout = time;
231362306a36Sopenharmony_ci	}
231462306a36Sopenharmony_ci	if (old_tail != ldata->read_tail) {
231562306a36Sopenharmony_ci		/*
231662306a36Sopenharmony_ci		 * Make sure no_room is not read in n_tty_kick_worker()
231762306a36Sopenharmony_ci		 * before setting ldata->read_tail in copy_from_read_buf().
231862306a36Sopenharmony_ci		 */
231962306a36Sopenharmony_ci		smp_mb();
232062306a36Sopenharmony_ci		n_tty_kick_worker(tty);
232162306a36Sopenharmony_ci	}
232262306a36Sopenharmony_ci	up_read(&tty->termios_rwsem);
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	remove_wait_queue(&tty->read_wait, &wait);
232562306a36Sopenharmony_ci	mutex_unlock(&ldata->atomic_read_lock);
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	if (kb - kbuf)
232862306a36Sopenharmony_ci		retval = kb - kbuf;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	return retval;
233162306a36Sopenharmony_ci}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci/**
233462306a36Sopenharmony_ci * n_tty_write		-	write function for tty
233562306a36Sopenharmony_ci * @tty: tty device
233662306a36Sopenharmony_ci * @file: file object
233762306a36Sopenharmony_ci * @buf: userspace buffer pointer
233862306a36Sopenharmony_ci * @nr: size of I/O
233962306a36Sopenharmony_ci *
234062306a36Sopenharmony_ci * Write function of the terminal device. This is serialized with respect to
234162306a36Sopenharmony_ci * other write callers but not to termios changes, reads and other such events.
234262306a36Sopenharmony_ci * Since the receive code will echo characters, thus calling driver write
234362306a36Sopenharmony_ci * methods, the %output_lock is used in the output processing functions called
234462306a36Sopenharmony_ci * here as well as in the echo processing function to protect the column state
234562306a36Sopenharmony_ci * and space left in the buffer.
234662306a36Sopenharmony_ci *
234762306a36Sopenharmony_ci * This code must be sure never to sleep through a hangup.
234862306a36Sopenharmony_ci *
234962306a36Sopenharmony_ci * Locking: output_lock to protect column state and space left
235062306a36Sopenharmony_ci *	 (note that the process_output*() functions take this lock themselves)
235162306a36Sopenharmony_ci */
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_cistatic ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
235462306a36Sopenharmony_ci			   const u8 *buf, size_t nr)
235562306a36Sopenharmony_ci{
235662306a36Sopenharmony_ci	const u8 *b = buf;
235762306a36Sopenharmony_ci	DEFINE_WAIT_FUNC(wait, woken_wake_function);
235862306a36Sopenharmony_ci	ssize_t num, retval = 0;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
236162306a36Sopenharmony_ci	if (L_TOSTOP(tty) && file->f_op->write_iter != redirected_tty_write) {
236262306a36Sopenharmony_ci		retval = tty_check_change(tty);
236362306a36Sopenharmony_ci		if (retval)
236462306a36Sopenharmony_ci			return retval;
236562306a36Sopenharmony_ci	}
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	down_read(&tty->termios_rwsem);
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	/* Write out any echoed characters that are still pending */
237062306a36Sopenharmony_ci	process_echoes(tty);
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	add_wait_queue(&tty->write_wait, &wait);
237362306a36Sopenharmony_ci	while (1) {
237462306a36Sopenharmony_ci		if (signal_pending(current)) {
237562306a36Sopenharmony_ci			retval = -ERESTARTSYS;
237662306a36Sopenharmony_ci			break;
237762306a36Sopenharmony_ci		}
237862306a36Sopenharmony_ci		if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
237962306a36Sopenharmony_ci			retval = -EIO;
238062306a36Sopenharmony_ci			break;
238162306a36Sopenharmony_ci		}
238262306a36Sopenharmony_ci		if (O_OPOST(tty)) {
238362306a36Sopenharmony_ci			while (nr > 0) {
238462306a36Sopenharmony_ci				num = process_output_block(tty, b, nr);
238562306a36Sopenharmony_ci				if (num < 0) {
238662306a36Sopenharmony_ci					if (num == -EAGAIN)
238762306a36Sopenharmony_ci						break;
238862306a36Sopenharmony_ci					retval = num;
238962306a36Sopenharmony_ci					goto break_out;
239062306a36Sopenharmony_ci				}
239162306a36Sopenharmony_ci				b += num;
239262306a36Sopenharmony_ci				nr -= num;
239362306a36Sopenharmony_ci				if (nr == 0)
239462306a36Sopenharmony_ci					break;
239562306a36Sopenharmony_ci				if (process_output(*b, tty) < 0)
239662306a36Sopenharmony_ci					break;
239762306a36Sopenharmony_ci				b++; nr--;
239862306a36Sopenharmony_ci			}
239962306a36Sopenharmony_ci			if (tty->ops->flush_chars)
240062306a36Sopenharmony_ci				tty->ops->flush_chars(tty);
240162306a36Sopenharmony_ci		} else {
240262306a36Sopenharmony_ci			struct n_tty_data *ldata = tty->disc_data;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci			while (nr > 0) {
240562306a36Sopenharmony_ci				mutex_lock(&ldata->output_lock);
240662306a36Sopenharmony_ci				num = tty->ops->write(tty, b, nr);
240762306a36Sopenharmony_ci				mutex_unlock(&ldata->output_lock);
240862306a36Sopenharmony_ci				if (num < 0) {
240962306a36Sopenharmony_ci					retval = num;
241062306a36Sopenharmony_ci					goto break_out;
241162306a36Sopenharmony_ci				}
241262306a36Sopenharmony_ci				if (!num)
241362306a36Sopenharmony_ci					break;
241462306a36Sopenharmony_ci				b += num;
241562306a36Sopenharmony_ci				nr -= num;
241662306a36Sopenharmony_ci			}
241762306a36Sopenharmony_ci		}
241862306a36Sopenharmony_ci		if (!nr)
241962306a36Sopenharmony_ci			break;
242062306a36Sopenharmony_ci		if (tty_io_nonblock(tty, file)) {
242162306a36Sopenharmony_ci			retval = -EAGAIN;
242262306a36Sopenharmony_ci			break;
242362306a36Sopenharmony_ci		}
242462306a36Sopenharmony_ci		up_read(&tty->termios_rwsem);
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci		wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci		down_read(&tty->termios_rwsem);
242962306a36Sopenharmony_ci	}
243062306a36Sopenharmony_cibreak_out:
243162306a36Sopenharmony_ci	remove_wait_queue(&tty->write_wait, &wait);
243262306a36Sopenharmony_ci	if (nr && tty->fasync)
243362306a36Sopenharmony_ci		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
243462306a36Sopenharmony_ci	up_read(&tty->termios_rwsem);
243562306a36Sopenharmony_ci	return (b - buf) ? b - buf : retval;
243662306a36Sopenharmony_ci}
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci/**
243962306a36Sopenharmony_ci * n_tty_poll		-	poll method for N_TTY
244062306a36Sopenharmony_ci * @tty: terminal device
244162306a36Sopenharmony_ci * @file: file accessing it
244262306a36Sopenharmony_ci * @wait: poll table
244362306a36Sopenharmony_ci *
244462306a36Sopenharmony_ci * Called when the line discipline is asked to poll() for data or for special
244562306a36Sopenharmony_ci * events. This code is not serialized with respect to other events save
244662306a36Sopenharmony_ci * open/close.
244762306a36Sopenharmony_ci *
244862306a36Sopenharmony_ci * This code must be sure never to sleep through a hangup.
244962306a36Sopenharmony_ci *
245062306a36Sopenharmony_ci * Locking: called without the kernel lock held -- fine.
245162306a36Sopenharmony_ci */
245262306a36Sopenharmony_cistatic __poll_t n_tty_poll(struct tty_struct *tty, struct file *file,
245362306a36Sopenharmony_ci							poll_table *wait)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	__poll_t mask = 0;
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	poll_wait(file, &tty->read_wait, wait);
245862306a36Sopenharmony_ci	poll_wait(file, &tty->write_wait, wait);
245962306a36Sopenharmony_ci	if (input_available_p(tty, 1))
246062306a36Sopenharmony_ci		mask |= EPOLLIN | EPOLLRDNORM;
246162306a36Sopenharmony_ci	else {
246262306a36Sopenharmony_ci		tty_buffer_flush_work(tty->port);
246362306a36Sopenharmony_ci		if (input_available_p(tty, 1))
246462306a36Sopenharmony_ci			mask |= EPOLLIN | EPOLLRDNORM;
246562306a36Sopenharmony_ci	}
246662306a36Sopenharmony_ci	if (tty->ctrl.packet && tty->link->ctrl.pktstatus)
246762306a36Sopenharmony_ci		mask |= EPOLLPRI | EPOLLIN | EPOLLRDNORM;
246862306a36Sopenharmony_ci	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
246962306a36Sopenharmony_ci		mask |= EPOLLHUP;
247062306a36Sopenharmony_ci	if (tty_hung_up_p(file))
247162306a36Sopenharmony_ci		mask |= EPOLLHUP;
247262306a36Sopenharmony_ci	if (tty->ops->write && !tty_is_writelocked(tty) &&
247362306a36Sopenharmony_ci			tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
247462306a36Sopenharmony_ci			tty_write_room(tty) > 0)
247562306a36Sopenharmony_ci		mask |= EPOLLOUT | EPOLLWRNORM;
247662306a36Sopenharmony_ci	return mask;
247762306a36Sopenharmony_ci}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_cistatic unsigned long inq_canon(struct n_tty_data *ldata)
248062306a36Sopenharmony_ci{
248162306a36Sopenharmony_ci	size_t nr, head, tail;
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	if (ldata->canon_head == ldata->read_tail)
248462306a36Sopenharmony_ci		return 0;
248562306a36Sopenharmony_ci	head = ldata->canon_head;
248662306a36Sopenharmony_ci	tail = ldata->read_tail;
248762306a36Sopenharmony_ci	nr = head - tail;
248862306a36Sopenharmony_ci	/* Skip EOF-chars.. */
248962306a36Sopenharmony_ci	while (MASK(head) != MASK(tail)) {
249062306a36Sopenharmony_ci		if (test_bit(MASK(tail), ldata->read_flags) &&
249162306a36Sopenharmony_ci		    read_buf(ldata, tail) == __DISABLED_CHAR)
249262306a36Sopenharmony_ci			nr--;
249362306a36Sopenharmony_ci		tail++;
249462306a36Sopenharmony_ci	}
249562306a36Sopenharmony_ci	return nr;
249662306a36Sopenharmony_ci}
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_cistatic int n_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
249962306a36Sopenharmony_ci		       unsigned long arg)
250062306a36Sopenharmony_ci{
250162306a36Sopenharmony_ci	struct n_tty_data *ldata = tty->disc_data;
250262306a36Sopenharmony_ci	int retval;
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	switch (cmd) {
250562306a36Sopenharmony_ci	case TIOCOUTQ:
250662306a36Sopenharmony_ci		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
250762306a36Sopenharmony_ci	case TIOCINQ:
250862306a36Sopenharmony_ci		down_write(&tty->termios_rwsem);
250962306a36Sopenharmony_ci		if (L_ICANON(tty) && !L_EXTPROC(tty))
251062306a36Sopenharmony_ci			retval = inq_canon(ldata);
251162306a36Sopenharmony_ci		else
251262306a36Sopenharmony_ci			retval = read_cnt(ldata);
251362306a36Sopenharmony_ci		up_write(&tty->termios_rwsem);
251462306a36Sopenharmony_ci		return put_user(retval, (unsigned int __user *) arg);
251562306a36Sopenharmony_ci	default:
251662306a36Sopenharmony_ci		return n_tty_ioctl_helper(tty, cmd, arg);
251762306a36Sopenharmony_ci	}
251862306a36Sopenharmony_ci}
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_cistatic struct tty_ldisc_ops n_tty_ops = {
252162306a36Sopenharmony_ci	.owner		 = THIS_MODULE,
252262306a36Sopenharmony_ci	.num		 = N_TTY,
252362306a36Sopenharmony_ci	.name            = "n_tty",
252462306a36Sopenharmony_ci	.open            = n_tty_open,
252562306a36Sopenharmony_ci	.close           = n_tty_close,
252662306a36Sopenharmony_ci	.flush_buffer    = n_tty_flush_buffer,
252762306a36Sopenharmony_ci	.read            = n_tty_read,
252862306a36Sopenharmony_ci	.write           = n_tty_write,
252962306a36Sopenharmony_ci	.ioctl           = n_tty_ioctl,
253062306a36Sopenharmony_ci	.set_termios     = n_tty_set_termios,
253162306a36Sopenharmony_ci	.poll            = n_tty_poll,
253262306a36Sopenharmony_ci	.receive_buf     = n_tty_receive_buf,
253362306a36Sopenharmony_ci	.write_wakeup    = n_tty_write_wakeup,
253462306a36Sopenharmony_ci	.receive_buf2	 = n_tty_receive_buf2,
253562306a36Sopenharmony_ci	.lookahead_buf	 = n_tty_lookahead_flow_ctrl,
253662306a36Sopenharmony_ci};
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci/**
253962306a36Sopenharmony_ci *	n_tty_inherit_ops	-	inherit N_TTY methods
254062306a36Sopenharmony_ci *	@ops: struct tty_ldisc_ops where to save N_TTY methods
254162306a36Sopenharmony_ci *
254262306a36Sopenharmony_ci *	Enables a 'subclass' line discipline to 'inherit' N_TTY methods.
254362306a36Sopenharmony_ci */
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_civoid n_tty_inherit_ops(struct tty_ldisc_ops *ops)
254662306a36Sopenharmony_ci{
254762306a36Sopenharmony_ci	*ops = n_tty_ops;
254862306a36Sopenharmony_ci	ops->owner = NULL;
254962306a36Sopenharmony_ci}
255062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(n_tty_inherit_ops);
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_civoid __init n_tty_init(void)
255362306a36Sopenharmony_ci{
255462306a36Sopenharmony_ci	tty_register_ldisc(&n_tty_ops);
255562306a36Sopenharmony_ci}
2556