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