Blame view

drivers/tty/n_tty.c 61.6 KB
e3b3d0f54   Greg Kroah-Hartman   tty: add SPDX ide...
1
  // SPDX-License-Identifier: GPL-1.0+
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  /*
   * n_tty.c --- implements the N_TTY line discipline.
4edf1827e   Alan Cox   n_tty: clean up o...
4
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
11
   * This code used to be in tty_io.c, but things are getting hairy
   * enough that it made sense to split things off.  (The N_TTY
   * processing has changed so much that it's hardly recognizable,
   * anyway...)
   *
   * Note that the open routine for N_TTY is guaranteed never to return
   * an error.  This is because Linux will fall back to setting a line
4edf1827e   Alan Cox   n_tty: clean up o...
12
   * to N_TTY if it can not switch to any other line discipline.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
   *
   * Written by Theodore Ts'o, Copyright 1994.
4edf1827e   Alan Cox   n_tty: clean up o...
15
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
   * This file also contains code originally written by Linus Torvalds,
   * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
4edf1827e   Alan Cox   n_tty: clean up o...
18
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
   * Reduced memory usage for older ARM systems  - Russell King.
   *
4edf1827e   Alan Cox   n_tty: clean up o...
21
   * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
   *		the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
   *		who actually finally proved there really was a race.
   *
   * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
   *		waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
11a96d182   Alan Cox   tty: rename the r...
27
   *		Also fixed a bug in BLOCKING mode where n_tty_write returns
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
   *		EAGAIN
   */
  
  #include <linux/types.h>
  #include <linux/major.h>
  #include <linux/errno.h>
  #include <linux/signal.h>
  #include <linux/fcntl.h>
  #include <linux/sched.h>
  #include <linux/interrupt.h>
  #include <linux/tty.h>
  #include <linux/timer.h>
  #include <linux/ctype.h>
  #include <linux/mm.h>
  #include <linux/string.h>
  #include <linux/slab.h>
  #include <linux/poll.h>
  #include <linux/bitops.h>
522ed7767   Miloslav Trmac   Audit: add TTY in...
46
47
  #include <linux/audit.h>
  #include <linux/file.h>
300a6204b   Alan Cox   n_tty: clean up c...
48
  #include <linux/uaccess.h>
572b9adbd   Rodolfo Giometti   ldisc n_tty: add ...
49
  #include <linux/module.h>
593fb1ae4   George Spelvin   pps: Move timesta...
50
  #include <linux/ratelimit.h>
86e35aea4   Peter Hurley   n_tty: Fix build ...
51
  #include <linux/vmalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

a5db48264   Valentin Vidic   n_tty: update com...
53
54
55
56
  /*
   * Until this number of characters is queued in the xmit buffer, select will
   * return "we have room for writes".
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
64
  #define WAKEUP_CHARS 256
  
  /*
   * This defines the low- and high-watermarks for throttling and
   * unthrottling the TTY driver.  These watermarks are used for
   * controlling the space in the read buffer.
   */
  #define TTY_THRESHOLD_THROTTLE		128 /* now based on remaining room */
bbd20759d   Thorsten Wißmann   drivers/tty: Remo...
65
  #define TTY_THRESHOLD_UNTHROTTLE	128
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

a88a69c91   Joe Peterson   n_tty: Fix loss o...
67
68
69
70
71
72
73
74
75
76
  /*
   * Special byte codes used in the echo buffer to represent operations
   * or special handling of characters.  Bytes in the echo buffer that
   * are not part of such special blocks are treated as normal character
   * codes.
   */
  #define ECHO_OP_START 0xff
  #define ECHO_OP_MOVE_BACK_COL 0x80
  #define ECHO_OP_SET_CANON_COL 0x81
  #define ECHO_OP_ERASE_TAB 0x82
cbfd0340a   Peter Hurley   n_tty: Process ec...
77
78
79
  #define ECHO_COMMIT_WATERMARK	256
  #define ECHO_BLOCK		256
  #define ECHO_DISCARD_WATERMARK	N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
32f13521c   Peter Hurley   n_tty: Line copy ...
80
81
82
83
  #undef N_TTY_TRACE
  #ifdef N_TTY_TRACE
  # define n_tty_trace(f, args...)	trace_printk(f, ##args)
  #else
a287885f1   Jiri Slaby   n_tty: check prin...
84
  # define n_tty_trace(f, args...)	no_printk(f, ##args)
32f13521c   Peter Hurley   n_tty: Line copy ...
85
  #endif
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
86
  struct n_tty_data {
fb7aa03db   Peter Hurley   n_tty: Separate b...
87
88
  	/* producer-published */
  	size_t read_head;
70aca71f9   Peter Hurley   n_tty: Fix unorde...
89
  	size_t commit_head;
fb7aa03db   Peter Hurley   n_tty: Separate b...
90
  	size_t canon_head;
9dfd16dde   Peter Hurley   n_tty: Avoid fals...
91
92
  	size_t echo_head;
  	size_t echo_commit;
1075a6e2d   Peter Hurley   n_tty: Fix appare...
93
  	size_t echo_mark;
1bb9d5628   Peter Hurley   n_tty: Rename pro...
94
  	DECLARE_BITMAP(char_map, 256);
fb7aa03db   Peter Hurley   n_tty: Separate b...
95
96
  
  	/* private to n_tty_receive_overrun (single-threaded) */
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
97
98
  	unsigned long overrun_time;
  	int num_overrun;
24a89d1cb   Peter Hurley   tty: Make ldisc i...
99
100
  	/* non-atomic */
  	bool no_room;
fb7aa03db   Peter Hurley   n_tty: Separate b...
101
  	/* must hold exclusive termios_rwsem to reset these */
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
102
  	unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
4d0ed1827   Peter Hurley   n_tty: Fix buffer...
103
  	unsigned char push:1;
3fe780b37   Jiri Slaby   TTY: move ldisc d...
104

fb7aa03db   Peter Hurley   n_tty: Separate b...
105
  	/* shared by producer and consumer */
20bafb3d2   Peter Hurley   n_tty: Move buffe...
106
  	char read_buf[N_TTY_BUF_SIZE];
3fe780b37   Jiri Slaby   TTY: move ldisc d...
107
  	DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
20bafb3d2   Peter Hurley   n_tty: Move buffe...
108
  	unsigned char echo_buf[N_TTY_BUF_SIZE];
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
109

fb7aa03db   Peter Hurley   n_tty: Separate b...
110
111
  	/* consumer-published */
  	size_t read_tail;
40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
112
  	size_t line_start;
fb7aa03db   Peter Hurley   n_tty: Separate b...
113

fb7aa03db   Peter Hurley   n_tty: Separate b...
114
115
  	/* protected by output lock */
  	unsigned int column;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
116
  	unsigned int canon_column;
9dfd16dde   Peter Hurley   n_tty: Avoid fals...
117
  	size_t echo_tail;
bddc7152f   Jiri Slaby   TTY: move ldisc d...
118
119
120
  
  	struct mutex atomic_read_lock;
  	struct mutex output_lock;
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
121
  };
3d63b7e4a   Tetsuo Handa   n_tty: Fix stall ...
122
  #define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1))
ce74117a1   Peter Hurley   n_tty: Get read_c...
123
124
  static inline size_t read_cnt(struct n_tty_data *ldata)
  {
a2f73be8e   Peter Hurley   n_tty: Remove rea...
125
  	return ldata->read_head - ldata->read_tail;
ce74117a1   Peter Hurley   n_tty: Get read_c...
126
  }
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
127
128
129
130
131
132
133
134
135
  static inline unsigned char read_buf(struct n_tty_data *ldata, size_t i)
  {
  	return ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)];
  }
  
  static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i)
  {
  	return &ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)];
  }
addaebccf   Peter Hurley   n_tty: Use separa...
136
137
  static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i)
  {
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
138
  	smp_rmb(); /* Matches smp_wmb() in add_echo_byte(). */
addaebccf   Peter Hurley   n_tty: Use separa...
139
140
141
142
143
144
145
  	return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
  }
  
  static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
  {
  	return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
  }
b97b3d9fb   Greg Kroah-Hartman   tty: wipe buffer ...
146
147
148
149
150
151
152
153
154
  /* If we are not echoing the data, perhaps this is a secret so erase it */
  static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size)
  {
  	bool icanon = !!L_ICANON(tty);
  	bool no_echo = !L_ECHO(tty);
  
  	if (icanon && no_echo)
  		memset(buffer, 0x00, size);
  }
679e7c299   Peter Hurley   n_tty: Uninline t...
155
156
  static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
  			    size_t tail, size_t n)
72586c606   Laura Abbott   n_tty: Fix auditi...
157
158
  {
  	struct n_tty_data *ldata = tty->disc_data;
679e7c299   Peter Hurley   n_tty: Uninline t...
159
  	size_t size = N_TTY_BUF_SIZE - tail;
b97b3d9fb   Greg Kroah-Hartman   tty: wipe buffer ...
160
  	void *from = read_buf_addr(ldata, tail);
679e7c299   Peter Hurley   n_tty: Uninline t...
161
162
163
  	int uncopied;
  
  	if (n > size) {
309426ae6   Peter Hurley   tty: audit: Remov...
164
  		tty_audit_add_data(tty, from, size);
679e7c299   Peter Hurley   n_tty: Uninline t...
165
  		uncopied = copy_to_user(to, from, size);
b97b3d9fb   Greg Kroah-Hartman   tty: wipe buffer ...
166
  		zero_buffer(tty, from, size - uncopied);
679e7c299   Peter Hurley   n_tty: Uninline t...
167
168
169
170
171
172
  		if (uncopied)
  			return uncopied;
  		to += size;
  		n -= size;
  		from = ldata->read_buf;
  	}
72586c606   Laura Abbott   n_tty: Fix auditi...
173

309426ae6   Peter Hurley   tty: audit: Remov...
174
  	tty_audit_add_data(tty, from, n);
b97b3d9fb   Greg Kroah-Hartman   tty: wipe buffer ...
175
176
177
  	uncopied = copy_to_user(to, from, n);
  	zero_buffer(tty, from, n - uncopied);
  	return uncopied;
72586c606   Laura Abbott   n_tty: Fix auditi...
178
  }
24a89d1cb   Peter Hurley   tty: Make ldisc i...
179
  /**
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
180
   *	n_tty_kick_worker - start input worker (if required)
24a89d1cb   Peter Hurley   tty: Make ldisc i...
181
182
   *	@tty: terminal
   *
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
183
   *	Re-schedules the flip buffer work if it may have stopped
24a89d1cb   Peter Hurley   tty: Make ldisc i...
184
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
185
186
187
188
   *	Caller holds exclusive termios_rwsem
   *	   or
   *	n_tty_read()/consumer path:
   *		holds non-exclusive termios_rwsem
24a89d1cb   Peter Hurley   tty: Make ldisc i...
189
   */
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
190
  static void n_tty_kick_worker(struct tty_struct *tty)
7879a9f9f   Peter Hurley   n_tty: Buffer wor...
191
  {
24a89d1cb   Peter Hurley   tty: Make ldisc i...
192
  	struct n_tty_data *ldata = tty->disc_data;
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
193
194
  	/* Did the input worker stop? Restart it */
  	if (unlikely(ldata->no_room)) {
24a89d1cb   Peter Hurley   tty: Make ldisc i...
195
  		ldata->no_room = 0;
ecbbfd44a   Jiri Slaby   TTY: move tty buf...
196
  		WARN_RATELIMIT(tty->port->itty == NULL,
cadf74869   Sasha Levin   tty: add missing ...
197
198
  				"scheduling with invalid itty
  ");
21622939f   Peter Hurley   tty: Add diagnost...
199
200
201
202
203
204
205
  		/* see if ldisc has been killed - if so, this means that
  		 * even though the ldisc has been halted and ->buf.work
  		 * cancelled, ->buf.work is about to be rescheduled
  		 */
  		WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
  			       "scheduling buffer work for halted ldisc
  ");
e176058f0   Peter Hurley   tty: Abstract tty...
206
  		tty_buffer_restart_work(tty->port);
ecbbfd44a   Jiri Slaby   TTY: move tty buf...
207
  	}
55db4c64e   Linus Torvalds   Revert "tty: make...
208
  }
9a4aec2dd   Peter Hurley   n_tty: Move chars...
209
210
211
212
213
214
  static ssize_t chars_in_buffer(struct tty_struct *tty)
  {
  	struct n_tty_data *ldata = tty->disc_data;
  	ssize_t n = 0;
  
  	if (!ldata->icanon)
70aca71f9   Peter Hurley   n_tty: Fix unorde...
215
  		n = ldata->commit_head - ldata->read_tail;
9a4aec2dd   Peter Hurley   n_tty: Move chars...
216
217
218
219
  	else
  		n = ldata->canon_head - ldata->read_tail;
  	return n;
  }
ee0bab83c   Peter Hurley   n_tty: Move n_tty...
220
221
222
223
224
225
226
227
228
229
230
  /**
   *	n_tty_write_wakeup	-	asynchronous I/O notifier
   *	@tty: tty device
   *
   *	Required for the ptys, serial driver etc. since processes
   *	that attach themselves to the master and rely on ASYNC
   *	IO must be woken up
   */
  
  static void n_tty_write_wakeup(struct tty_struct *tty)
  {
7bccc3654   Peter Hurley   n_tty: Fix stuck ...
231
232
  	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
  	kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
ee0bab83c   Peter Hurley   n_tty: Move n_tty...
233
  }
4a23a4df5   Peter Hurley   n_tty: Factor 're...
234
  static void n_tty_check_throttle(struct tty_struct *tty)
6367ca72f   Peter Hurley   n_tty: Factor thr...
235
  {
a342846f9   Peter Hurley   n_tty: Fix thrott...
236
  	struct n_tty_data *ldata = tty->disc_data;
6367ca72f   Peter Hurley   n_tty: Factor thr...
237
238
239
240
241
  	/*
  	 * Check the remaining room for the input canonicalization
  	 * mode.  We don't want to throttle the driver if we're in
  	 * canonical mode and don't have a newline yet!
  	 */
a342846f9   Peter Hurley   n_tty: Fix thrott...
242
243
  	if (ldata->icanon && ldata->canon_head == ldata->read_tail)
  		return;
6367ca72f   Peter Hurley   n_tty: Factor thr...
244
245
246
  	while (1) {
  		int throttled;
  		tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
5e28cca15   Peter Hurley   n_tty: Simplify t...
247
  		if (N_TTY_BUF_SIZE - read_cnt(ldata) >= TTY_THRESHOLD_THROTTLE)
6367ca72f   Peter Hurley   n_tty: Factor thr...
248
249
250
251
252
253
254
  			break;
  		throttled = tty_throttle_safe(tty);
  		if (!throttled)
  			break;
  	}
  	__tty_set_flow_change(tty, 0);
  }
4b293492a   Peter Hurley   n_tty: Un-inline ...
255
  static void n_tty_check_unthrottle(struct tty_struct *tty)
6367ca72f   Peter Hurley   n_tty: Factor thr...
256
  {
6d27a63ca   Peter Hurley   n_tty: Fix unsafe...
257
  	if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
3afb1b394   Peter Hurley   n_tty: Special ca...
258
259
  		if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
  			return;
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
260
  		n_tty_kick_worker(tty);
6d27a63ca   Peter Hurley   n_tty: Fix unsafe...
261
  		tty_wakeup(tty->link);
3afb1b394   Peter Hurley   n_tty: Special ca...
262
263
  		return;
  	}
6367ca72f   Peter Hurley   n_tty: Factor thr...
264
265
266
267
268
269
270
271
272
273
274
275
276
  	/* If there is enough space in the read buffer now, let the
  	 * low-level driver know. We use chars_in_buffer() to
  	 * check the buffer, as it now knows about canonical mode.
  	 * Otherwise, if the driver is throttled and the line is
  	 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
  	 * we won't get any more characters.
  	 */
  
  	while (1) {
  		int unthrottled;
  		tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
  		if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
  			break;
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
277
  		n_tty_kick_worker(tty);
6367ca72f   Peter Hurley   n_tty: Factor thr...
278
279
280
281
282
283
  		unthrottled = tty_unthrottle_safe(tty);
  		if (!unthrottled)
  			break;
  	}
  	__tty_set_flow_change(tty, 0);
  }
17b820606   Alan Cox   tty: Minor tidyup...
284
285
286
  /**
   *	put_tty_queue		-	add character to tty
   *	@c: character
57c941212   Jiri Slaby   TTY: n_tty, propa...
287
   *	@ldata: n_tty data
17b820606   Alan Cox   tty: Minor tidyup...
288
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
289
290
291
292
   *	Add a character to the tty read_buf queue.
   *
   *	n_tty_receive_buf()/producer path:
   *		caller holds non-exclusive termios_rwsem
17b820606   Alan Cox   tty: Minor tidyup...
293
   */
19e2ad6a0   Peter Hurley   n_tty: Remove ove...
294
  static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  {
8bfbe2de7   Christian Riesch   n_tty: Fix read_b...
296
297
  	*read_buf_addr(ldata, ldata->read_head) = c;
  	ldata->read_head++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
  }
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
   *	reset_buffer_flags	-	reset buffer state
   *	@tty: terminal to reset
   *
25518c68b   Peter Hurley   n_tty: Correct un...
304
305
   *	Reset the read buffer counters and clear the flags.
   *	Called from n_tty_open() and n_tty_flush_buffer().
17b820606   Alan Cox   tty: Minor tidyup...
306
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
307
308
   *	Locking: caller holds exclusive termios_rwsem
   *		 (or locking is not required)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
   */
a88a69c91   Joe Peterson   n_tty: Fix loss o...
310

b66f4fa50   Peter Hurley   n_tty: Fully init...
311
  static void reset_buffer_flags(struct n_tty_data *ldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  {
a73d3d698   Peter Hurley   n_tty: Replace ca...
313
  	ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
70aca71f9   Peter Hurley   n_tty: Fix unorde...
314
  	ldata->commit_head = 0;
40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
315
  	ldata->line_start = 0;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
316

a73d3d698   Peter Hurley   n_tty: Replace ca...
317
  	ldata->erasing = 0;
3fe780b37   Jiri Slaby   TTY: move ldisc d...
318
  	bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
4d0ed1827   Peter Hurley   n_tty: Fix buffer...
319
  	ldata->push = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
  }
a30737ab7   Peter Hurley   n_tty: Factor pac...
321
322
323
  static void n_tty_packet_mode_flush(struct tty_struct *tty)
  {
  	unsigned long flags;
a30737ab7   Peter Hurley   n_tty: Factor pac...
324
  	if (tty->link->packet) {
54e8e5fca   Peter Hurley   pty: Don't claim ...
325
  		spin_lock_irqsave(&tty->ctrl_lock, flags);
a30737ab7   Peter Hurley   n_tty: Factor pac...
326
  		tty->ctrl_status |= TIOCPKT_FLUSHREAD;
54e8e5fca   Peter Hurley   pty: Don't claim ...
327
  		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
e81107d4c   Kosuke Tatsukawa   tty: fix stall ca...
328
  		wake_up_interruptible(&tty->link->read_wait);
a30737ab7   Peter Hurley   n_tty: Factor pac...
329
  	}
a30737ab7   Peter Hurley   n_tty: Factor pac...
330
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
  /**
   *	n_tty_flush_buffer	-	clean input queue
   *	@tty:	terminal device
   *
25518c68b   Peter Hurley   n_tty: Correct un...
335
336
337
   *	Flush the input buffer. Called when the tty layer wants the
   *	buffer flushed (eg at hangup) or when the N_TTY line discipline
   *	internally has to clean the pending queue (for example some signals).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
339
340
341
342
   *	Holds termios_rwsem to exclude producer/consumer while
   *	buffer indices are reset.
   *
   *	Locking: ctrl_lock, exclusive termios_rwsem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
   */
4edf1827e   Alan Cox   n_tty: clean up o...
344
345
  
  static void n_tty_flush_buffer(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  {
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
347
  	down_write(&tty->termios_rwsem);
b66f4fa50   Peter Hurley   n_tty: Fully init...
348
  	reset_buffer_flags(tty->disc_data);
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
349
  	n_tty_kick_worker(tty);
4edf1827e   Alan Cox   n_tty: clean up o...
350

a30737ab7   Peter Hurley   n_tty: Factor pac...
351
352
  	if (tty->link)
  		n_tty_packet_mode_flush(tty);
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
353
  	up_write(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  }
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
355
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
359
360
361
362
   *	is_utf8_continuation	-	utf8 multibyte check
   *	@c: byte to check
   *
   *	Returns true if the utf8 character 'c' is a multibyte continuation
   *	character. We use this to correctly compute the on screen size
   *	of the character when printing
   */
4edf1827e   Alan Cox   n_tty: clean up o...
363

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
367
368
369
370
371
372
373
374
375
  static inline int is_utf8_continuation(unsigned char c)
  {
  	return (c & 0xc0) == 0x80;
  }
  
  /**
   *	is_continuation		-	multibyte check
   *	@c: byte to check
   *
   *	Returns true if the utf8 character 'c' is a multibyte continuation
   *	character and the terminal is in unicode mode.
   */
4edf1827e   Alan Cox   n_tty: clean up o...
376

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
381
382
  static inline int is_continuation(unsigned char c, struct tty_struct *tty)
  {
  	return I_IUTF8(tty) && is_utf8_continuation(c);
  }
  
  /**
a88a69c91   Joe Peterson   n_tty: Fix loss o...
383
   *	do_output_char			-	output one character
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
   *	@c: character (or partial unicode symbol)
   *	@tty: terminal device
a88a69c91   Joe Peterson   n_tty: Fix loss o...
386
   *	@space: space available in tty driver write buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
   *
a88a69c91   Joe Peterson   n_tty: Fix loss o...
388
389
   *	This is a helper function that handles one output character
   *	(including special characters like TAB, CR, LF, etc.),
ee5aa7b8b   Joe Peterson   n_tty: honor opos...
390
391
   *	doing OPOST processing and putting the results in the
   *	tty driver's write buffer.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
392
393
394
395
   *
   *	Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
   *	and NLDLY.  They simply aren't relevant in the world today.
   *	If you ever need them, add them here.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
   *
a88a69c91   Joe Peterson   n_tty: Fix loss o...
397
398
399
400
401
   *	Returns the number of bytes of buffer space used or -1 if
   *	no space left.
   *
   *	Locking: should be called under the output_lock to protect
   *		 the column state and space left in the buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
   */
4edf1827e   Alan Cox   n_tty: clean up o...
403

a88a69c91   Joe Peterson   n_tty: Fix loss o...
404
  static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
406
  	struct n_tty_data *ldata = tty->disc_data;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
407
  	int	spaces;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
  	if (!space)
  		return -1;
300a6204b   Alan Cox   n_tty: clean up c...
411

a88a69c91   Joe Peterson   n_tty: Fix loss o...
412
413
414
415
  	switch (c) {
  	case '
  ':
  		if (O_ONLRET(tty))
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
416
  			ldata->column = 0;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
417
418
419
  		if (O_ONLCR(tty)) {
  			if (space < 2)
  				return -1;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
420
  			ldata->canon_column = ldata->column = 0;
37f81fa1f   Linus Torvalds   n_tty: do O_ONLCR...
421
422
  			tty->ops->write(tty, "\r
  ", 2);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
423
424
  			return 2;
  		}
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
425
  		ldata->canon_column = ldata->column;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
426
427
  		break;
  	case '\r':
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
428
  		if (O_ONOCR(tty) && ldata->column == 0)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
429
430
431
432
433
  			return 0;
  		if (O_OCRNL(tty)) {
  			c = '
  ';
  			if (O_ONLRET(tty))
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
434
  				ldata->canon_column = ldata->column = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  			break;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
436
  		}
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
437
  		ldata->canon_column = ldata->column = 0;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
438
439
  		break;
  	case '\t':
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
440
  		spaces = 8 - (ldata->column & 7);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
441
442
443
  		if (O_TABDLY(tty) == XTABS) {
  			if (space < spaces)
  				return -1;
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
444
  			ldata->column += spaces;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
445
446
  			tty->ops->write(tty, "        ", spaces);
  			return spaces;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  		}
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
448
  		ldata->column += spaces;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
449
450
  		break;
  	case '\b':
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
451
452
  		if (ldata->column > 0)
  			ldata->column--;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
453
454
  		break;
  	default:
a59c0d6f1   Joe Peterson   n_tty: Fix handli...
455
456
457
458
  		if (!iscntrl(c)) {
  			if (O_OLCUC(tty))
  				c = toupper(c);
  			if (!is_continuation(c, tty))
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
459
  				ldata->column++;
a59c0d6f1   Joe Peterson   n_tty: Fix handli...
460
  		}
a88a69c91   Joe Peterson   n_tty: Fix loss o...
461
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  	}
a88a69c91   Joe Peterson   n_tty: Fix loss o...
463

f34d7a5b7   Alan Cox   tty: The big oper...
464
  	tty_put_char(tty, c);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
465
466
467
468
469
470
471
472
  	return 1;
  }
  
  /**
   *	process_output			-	output post processor
   *	@c: character (or partial unicode symbol)
   *	@tty: terminal device
   *
ee5aa7b8b   Joe Peterson   n_tty: honor opos...
473
474
475
   *	Output one character with OPOST processing.
   *	Returns -1 when the output device is full and the character
   *	must be retried.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
476
477
478
479
480
481
482
483
   *
   *	Locking: output_lock to protect column state and space left
   *		 (also, this is called from n_tty_write under the
   *		  tty layer write lock)
   */
  
  static int process_output(unsigned char c, struct tty_struct *tty)
  {
bddc7152f   Jiri Slaby   TTY: move ldisc d...
484
  	struct n_tty_data *ldata = tty->disc_data;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
485
  	int	space, retval;
bddc7152f   Jiri Slaby   TTY: move ldisc d...
486
  	mutex_lock(&ldata->output_lock);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
487
488
489
  
  	space = tty_write_room(tty);
  	retval = do_output_char(c, tty, space);
bddc7152f   Jiri Slaby   TTY: move ldisc d...
490
  	mutex_unlock(&ldata->output_lock);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
491
492
493
494
  	if (retval < 0)
  		return -1;
  	else
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
  }
  
  /**
a88a69c91   Joe Peterson   n_tty: Fix loss o...
498
   *	process_output_block		-	block post processor
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
   *	@tty: terminal device
ee5aa7b8b   Joe Peterson   n_tty: honor opos...
500
501
502
503
504
   *	@buf: character buffer
   *	@nr: number of bytes to output
   *
   *	Output a block of characters with OPOST processing.
   *	Returns the number of characters output.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
510
   *
   *	This path is used to speed up block console writes, among other
   *	things when processing blocks of output data. It handles only
   *	the simple cases normally found and helps to generate blocks of
   *	symbols for the console driver and thus improve performance.
   *
a88a69c91   Joe Peterson   n_tty: Fix loss o...
511
512
513
   *	Locking: output_lock to protect column state and space left
   *		 (also, this is called from n_tty_write under the
   *		  tty layer write lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
   */
4edf1827e   Alan Cox   n_tty: clean up o...
515

a88a69c91   Joe Peterson   n_tty: Fix loss o...
516
517
  static ssize_t process_output_block(struct tty_struct *tty,
  				    const unsigned char *buf, unsigned int nr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
519
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  	int	space;
bbd20759d   Thorsten Wißmann   drivers/tty: Remo...
521
  	int	i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  	const unsigned char *cp;
bddc7152f   Jiri Slaby   TTY: move ldisc d...
523
  	mutex_lock(&ldata->output_lock);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
524

f34d7a5b7   Alan Cox   tty: The big oper...
525
  	space = tty_write_room(tty);
9ef8927f4   Colin Ian King   n_tty: check for ...
526
  	if (space <= 0) {
bddc7152f   Jiri Slaby   TTY: move ldisc d...
527
  		mutex_unlock(&ldata->output_lock);
9ef8927f4   Colin Ian King   n_tty: check for ...
528
  		return space;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
529
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
532
533
  	if (nr > space)
  		nr = space;
  
  	for (i = 0, cp = buf; i < nr; i++, cp++) {
a59c0d6f1   Joe Peterson   n_tty: Fix handli...
534
535
536
  		unsigned char c = *cp;
  
  		switch (c) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
  		case '
  ':
  			if (O_ONLRET(tty))
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
540
  				ldata->column = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
  			if (O_ONLCR(tty))
  				goto break_out;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
543
  			ldata->canon_column = ldata->column;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
  			break;
  		case '\r':
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
546
  			if (O_ONOCR(tty) && ldata->column == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
549
  				goto break_out;
  			if (O_OCRNL(tty))
  				goto break_out;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
550
  			ldata->canon_column = ldata->column = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
  			break;
  		case '\t':
  			goto break_out;
  		case '\b':
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
555
556
  			if (ldata->column > 0)
  				ldata->column--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
558
  			break;
  		default:
a59c0d6f1   Joe Peterson   n_tty: Fix handli...
559
560
561
562
  			if (!iscntrl(c)) {
  				if (O_OLCUC(tty))
  					goto break_out;
  				if (!is_continuation(c, tty))
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
563
  					ldata->column++;
a59c0d6f1   Joe Peterson   n_tty: Fix handli...
564
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
  			break;
  		}
  	}
  break_out:
f34d7a5b7   Alan Cox   tty: The big oper...
569
  	i = tty->ops->write(tty, buf, i);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
570

bddc7152f   Jiri Slaby   TTY: move ldisc d...
571
  	mutex_unlock(&ldata->output_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  	return i;
  }
a88a69c91   Joe Peterson   n_tty: Fix loss o...
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  /**
   *	process_echoes	-	write pending echo characters
   *	@tty: terminal device
   *
   *	Write previously buffered echo (and other ldisc-generated)
   *	characters to the tty.
   *
   *	Characters generated by the ldisc (including echoes) need to
   *	be buffered because the driver's write buffer can fill during
   *	heavy program output.  Echoing straight to the driver will
   *	often fail under these conditions, causing lost characters and
   *	resulting mismatches of ldisc state information.
   *
   *	Since the ldisc state must represent the characters actually sent
   *	to the driver at the time of the write, operations like certain
   *	changes in column state are also saved in the buffer and executed
   *	here.
   *
   *	A circular fifo buffer is used so that the most recent characters
   *	are prioritized.  Also, when control characters are echoed with a
   *	prefixed "^", the pair is treated atomically and thus not separated.
   *
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
596
   *	Locking: callers must hold output_lock
a88a69c91   Joe Peterson   n_tty: Fix loss o...
597
   */
bc5b1ec58   Peter Hurley   n_tty: Only flush...
598
  static size_t __process_echoes(struct tty_struct *tty)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
599
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
600
  	struct n_tty_data *ldata = tty->disc_data;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
601
  	int	space, old_space;
addaebccf   Peter Hurley   n_tty: Use separa...
602
  	size_t tail;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
603
  	unsigned char c;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
604

bc5b1ec58   Peter Hurley   n_tty: Only flush...
605
  	old_space = space = tty_write_room(tty);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
606

addaebccf   Peter Hurley   n_tty: Use separa...
607
  	tail = ldata->echo_tail;
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
608
  	while (MASK(ldata->echo_commit) != MASK(tail)) {
addaebccf   Peter Hurley   n_tty: Use separa...
609
  		c = echo_buf(ldata, tail);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
610
611
  		if (c == ECHO_OP_START) {
  			unsigned char op;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
612
613
614
  			int no_space_left = 0;
  
  			/*
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
615
616
617
618
619
620
621
  			 * Since add_echo_byte() is called without holding
  			 * output_lock, we might see only portion of multi-byte
  			 * operation.
  			 */
  			if (MASK(ldata->echo_commit) == MASK(tail + 1))
  				goto not_yet_stored;
  			/*
a88a69c91   Joe Peterson   n_tty: Fix loss o...
622
623
624
625
  			 * If the buffer byte is the start of a multi-byte
  			 * operation, get the next byte, which is either the
  			 * op code or a control character value.
  			 */
addaebccf   Peter Hurley   n_tty: Use separa...
626
  			op = echo_buf(ldata, tail + 1);
300a6204b   Alan Cox   n_tty: clean up c...
627

a88a69c91   Joe Peterson   n_tty: Fix loss o...
628
  			switch (op) {
e24cd4e6d   Kees Cook   n_tty: Distribute...
629
  			case ECHO_OP_ERASE_TAB: {
a88a69c91   Joe Peterson   n_tty: Fix loss o...
630
  				unsigned int num_chars, num_bs;
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
631
632
  				if (MASK(ldata->echo_commit) == MASK(tail + 2))
  					goto not_yet_stored;
addaebccf   Peter Hurley   n_tty: Use separa...
633
  				num_chars = echo_buf(ldata, tail + 2);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
634
635
636
637
638
639
640
641
642
643
644
645
  
  				/*
  				 * Determine how many columns to go back
  				 * in order to erase the tab.
  				 * This depends on the number of columns
  				 * used by other characters within the tab
  				 * area.  If this (modulo 8) count is from
  				 * the start of input rather than from a
  				 * previous tab, we offset by canon column.
  				 * Otherwise, tab spacing is normal.
  				 */
  				if (!(num_chars & 0x80))
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
646
  					num_chars += ldata->canon_column;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
647
648
649
650
651
652
653
654
655
  				num_bs = 8 - (num_chars & 7);
  
  				if (num_bs > space) {
  					no_space_left = 1;
  					break;
  				}
  				space -= num_bs;
  				while (num_bs--) {
  					tty_put_char(tty, '\b');
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
656
657
  					if (ldata->column > 0)
  						ldata->column--;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
658
  				}
addaebccf   Peter Hurley   n_tty: Use separa...
659
  				tail += 3;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
660
  				break;
e24cd4e6d   Kees Cook   n_tty: Distribute...
661
  			}
a88a69c91   Joe Peterson   n_tty: Fix loss o...
662
  			case ECHO_OP_SET_CANON_COL:
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
663
  				ldata->canon_column = ldata->column;
addaebccf   Peter Hurley   n_tty: Use separa...
664
  				tail += 2;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
665
666
667
  				break;
  
  			case ECHO_OP_MOVE_BACK_COL:
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
668
669
  				if (ldata->column > 0)
  					ldata->column--;
addaebccf   Peter Hurley   n_tty: Use separa...
670
  				tail += 2;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
671
672
673
674
675
676
677
678
679
  				break;
  
  			case ECHO_OP_START:
  				/* This is an escaped echo op start code */
  				if (!space) {
  					no_space_left = 1;
  					break;
  				}
  				tty_put_char(tty, ECHO_OP_START);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
680
  				ldata->column++;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
681
  				space--;
addaebccf   Peter Hurley   n_tty: Use separa...
682
  				tail += 2;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
683
684
685
  				break;
  
  			default:
a88a69c91   Joe Peterson   n_tty: Fix loss o...
686
  				/*
62b263585   Joe Peterson   n_tty: move echoc...
687
688
689
690
691
692
693
  				 * If the op is not a special byte code,
  				 * it is a ctrl char tagged to be echoed
  				 * as "^X" (where X is the letter
  				 * representing the control char).
  				 * Note that we must ensure there is
  				 * enough space for the whole ctrl pair.
  				 *
a88a69c91   Joe Peterson   n_tty: Fix loss o...
694
  				 */
62b263585   Joe Peterson   n_tty: move echoc...
695
696
697
698
699
700
  				if (space < 2) {
  					no_space_left = 1;
  					break;
  				}
  				tty_put_char(tty, '^');
  				tty_put_char(tty, op ^ 0100);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
701
  				ldata->column += 2;
62b263585   Joe Peterson   n_tty: move echoc...
702
  				space -= 2;
addaebccf   Peter Hurley   n_tty: Use separa...
703
  				tail += 2;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
704
705
706
707
708
  			}
  
  			if (no_space_left)
  				break;
  		} else {
582f55907   Peter Hurley   tty: Remove TTY_H...
709
  			if (O_OPOST(tty)) {
ee5aa7b8b   Joe Peterson   n_tty: honor opos...
710
711
712
713
714
715
716
717
718
719
  				int retval = do_output_char(c, tty, space);
  				if (retval < 0)
  					break;
  				space -= retval;
  			} else {
  				if (!space)
  					break;
  				tty_put_char(tty, c);
  				space -= 1;
  			}
addaebccf   Peter Hurley   n_tty: Use separa...
720
  			tail += 1;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
721
  		}
a88a69c91   Joe Peterson   n_tty: Fix loss o...
722
  	}
cbfd0340a   Peter Hurley   n_tty: Process ec...
723
724
725
  	/* If the echo buffer is nearly full (so that the possibility exists
  	 * of echo overrun before the next commit), then discard enough
  	 * data at the tail to prevent a subsequent overrun */
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
726
727
  	while (ldata->echo_commit > tail &&
  	       ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
c476f6584   Roel Kluin   tty: incorrect te...
728
  		if (echo_buf(ldata, tail) == ECHO_OP_START) {
6f2225363   Peter Hurley   n_tty: Fix echo o...
729
  			if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB)
cbfd0340a   Peter Hurley   n_tty: Process ec...
730
731
732
733
734
735
  				tail += 3;
  			else
  				tail += 2;
  		} else
  			tail++;
  	}
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
736
   not_yet_stored:
addaebccf   Peter Hurley   n_tty: Use separa...
737
  	ldata->echo_tail = tail;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
738
  	return old_space - space;
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
739
740
741
742
743
  }
  
  static void commit_echoes(struct tty_struct *tty)
  {
  	struct n_tty_data *ldata = tty->disc_data;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
744
  	size_t nr, old, echoed;
cbfd0340a   Peter Hurley   n_tty: Process ec...
745
  	size_t head;
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
746
  	mutex_lock(&ldata->output_lock);
cbfd0340a   Peter Hurley   n_tty: Process ec...
747
  	head = ldata->echo_head;
1075a6e2d   Peter Hurley   n_tty: Fix appare...
748
  	ldata->echo_mark = head;
cbfd0340a   Peter Hurley   n_tty: Process ec...
749
750
751
752
753
754
  	old = ldata->echo_commit - ldata->echo_tail;
  
  	/* Process committed echoes if the accumulated # of bytes
  	 * is over the threshold (and try again each time another
  	 * block is accumulated) */
  	nr = head - ldata->echo_tail;
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
755
756
757
  	if (nr < ECHO_COMMIT_WATERMARK ||
  	    (nr % ECHO_BLOCK > old % ECHO_BLOCK)) {
  		mutex_unlock(&ldata->output_lock);
cbfd0340a   Peter Hurley   n_tty: Process ec...
758
  		return;
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
759
  	}
a88a69c91   Joe Peterson   n_tty: Fix loss o...
760

cbfd0340a   Peter Hurley   n_tty: Process ec...
761
  	ldata->echo_commit = head;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
762
  	echoed = __process_echoes(tty);
bddc7152f   Jiri Slaby   TTY: move ldisc d...
763
  	mutex_unlock(&ldata->output_lock);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
764

bc5b1ec58   Peter Hurley   n_tty: Only flush...
765
  	if (echoed && tty->ops->flush_chars)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
766
767
  		tty->ops->flush_chars(tty);
  }
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
768
  static void process_echoes(struct tty_struct *tty)
17bd79074   Peter Hurley   n_tty: Remove ech...
769
770
  {
  	struct n_tty_data *ldata = tty->disc_data;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
771
  	size_t echoed;
17bd79074   Peter Hurley   n_tty: Remove ech...
772

e2613be50   Peter Hurley   n_tty: Fix stale ...
773
  	if (ldata->echo_mark == ldata->echo_tail)
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
774
775
776
  		return;
  
  	mutex_lock(&ldata->output_lock);
1075a6e2d   Peter Hurley   n_tty: Fix appare...
777
  	ldata->echo_commit = ldata->echo_mark;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
778
  	echoed = __process_echoes(tty);
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
779
  	mutex_unlock(&ldata->output_lock);
bc5b1ec58   Peter Hurley   n_tty: Only flush...
780
  	if (echoed && tty->ops->flush_chars)
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
781
  		tty->ops->flush_chars(tty);
17bd79074   Peter Hurley   n_tty: Remove ech...
782
  }
1075a6e2d   Peter Hurley   n_tty: Fix appare...
783
  /* NB: echo_mark and echo_head should be equivalent here */
cbfd0340a   Peter Hurley   n_tty: Process ec...
784
785
786
  static void flush_echoes(struct tty_struct *tty)
  {
  	struct n_tty_data *ldata = tty->disc_data;
39434abd9   Peter Hurley   n_tty: Fix missin...
787
788
  	if ((!L_ECHO(tty) && !L_ECHONL(tty)) ||
  	    ldata->echo_commit == ldata->echo_head)
cbfd0340a   Peter Hurley   n_tty: Process ec...
789
790
791
792
793
794
795
  		return;
  
  	mutex_lock(&ldata->output_lock);
  	ldata->echo_commit = ldata->echo_head;
  	__process_echoes(tty);
  	mutex_unlock(&ldata->output_lock);
  }
a88a69c91   Joe Peterson   n_tty: Fix loss o...
796
797
798
  /**
   *	add_echo_byte	-	add a byte to the echo buffer
   *	@c: unicode byte to echo
57c941212   Jiri Slaby   TTY: n_tty, propa...
799
   *	@ldata: n_tty data
a88a69c91   Joe Peterson   n_tty: Fix loss o...
800
801
   *
   *	Add a character or operation byte to the echo buffer.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
802
   */
cbfd0340a   Peter Hurley   n_tty: Process ec...
803
  static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
804
  {
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
805
806
807
  	*echo_buf_addr(ldata, ldata->echo_head) = c;
  	smp_wmb(); /* Matches smp_rmb() in echo_buf(). */
  	ldata->echo_head++;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
808
809
810
811
  }
  
  /**
   *	echo_move_back_col	-	add operation to move back a column
57c941212   Jiri Slaby   TTY: n_tty, propa...
812
   *	@ldata: n_tty data
a88a69c91   Joe Peterson   n_tty: Fix loss o...
813
814
   *
   *	Add an operation to the echo buffer to move back one column.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
815
   */
57c941212   Jiri Slaby   TTY: n_tty, propa...
816
  static void echo_move_back_col(struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
817
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
818
819
  	add_echo_byte(ECHO_OP_START, ldata);
  	add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
820
821
822
823
  }
  
  /**
   *	echo_set_canon_col	-	add operation to set the canon column
57c941212   Jiri Slaby   TTY: n_tty, propa...
824
   *	@ldata: n_tty data
a88a69c91   Joe Peterson   n_tty: Fix loss o...
825
826
827
   *
   *	Add an operation to the echo buffer to set the canon column
   *	to the current column.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
828
   */
57c941212   Jiri Slaby   TTY: n_tty, propa...
829
  static void echo_set_canon_col(struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
830
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
831
832
  	add_echo_byte(ECHO_OP_START, ldata);
  	add_echo_byte(ECHO_OP_SET_CANON_COL, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
833
834
835
836
837
838
  }
  
  /**
   *	echo_erase_tab	-	add operation to erase a tab
   *	@num_chars: number of character columns already used
   *	@after_tab: true if num_chars starts after a previous tab
57c941212   Jiri Slaby   TTY: n_tty, propa...
839
   *	@ldata: n_tty data
a88a69c91   Joe Peterson   n_tty: Fix loss o...
840
841
842
843
844
845
846
847
   *
   *	Add an operation to the echo buffer to erase a tab.
   *
   *	Called by the eraser function, which knows how many character
   *	columns have been used since either a previous tab or the start
   *	of input.  This information will be used later, along with
   *	canon column (if applicable), to go back the correct number
   *	of columns.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
848
849
850
   */
  
  static void echo_erase_tab(unsigned int num_chars, int after_tab,
57c941212   Jiri Slaby   TTY: n_tty, propa...
851
  			   struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
852
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
853
854
  	add_echo_byte(ECHO_OP_START, ldata);
  	add_echo_byte(ECHO_OP_ERASE_TAB, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
855
856
857
858
859
860
861
  
  	/* We only need to know this modulo 8 (tab spacing) */
  	num_chars &= 7;
  
  	/* Set the high bit as a flag if num_chars is after a previous tab */
  	if (after_tab)
  		num_chars |= 0x80;
300a6204b   Alan Cox   n_tty: clean up c...
862

57c941212   Jiri Slaby   TTY: n_tty, propa...
863
  	add_echo_byte(num_chars, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
864
865
866
867
868
869
870
871
872
873
874
  }
  
  /**
   *	echo_char_raw	-	echo a character raw
   *	@c: unicode byte to echo
   *	@tty: terminal device
   *
   *	Echo user input back onto the screen. This must be called only when
   *	L_ECHO(tty) is true. Called from the driver receive_buf path.
   *
   *	This variant does not treat control characters specially.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
875
   */
57c941212   Jiri Slaby   TTY: n_tty, propa...
876
  static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
877
  {
a88a69c91   Joe Peterson   n_tty: Fix loss o...
878
  	if (c == ECHO_OP_START) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
879
880
  		add_echo_byte(ECHO_OP_START, ldata);
  		add_echo_byte(ECHO_OP_START, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
881
  	} else {
57c941212   Jiri Slaby   TTY: n_tty, propa...
882
  		add_echo_byte(c, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
883
  	}
a88a69c91   Joe Peterson   n_tty: Fix loss o...
884
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
  
  /**
a88a69c91   Joe Peterson   n_tty: Fix loss o...
887
   *	echo_char	-	echo a character
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
890
   *	@c: unicode byte to echo
   *	@tty: terminal device
   *
4edf1827e   Alan Cox   n_tty: clean up o...
891
   *	Echo user input back onto the screen. This must be called only when
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
   *	L_ECHO(tty) is true. Called from the driver receive_buf path.
17b820606   Alan Cox   tty: Minor tidyup...
893
   *
62b263585   Joe Peterson   n_tty: move echoc...
894
895
   *	This variant tags control characters to be echoed as "^X"
   *	(where X is the letter representing the control char).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
   */
  
  static void echo_char(unsigned char c, struct tty_struct *tty)
  {
bddc7152f   Jiri Slaby   TTY: move ldisc d...
900
  	struct n_tty_data *ldata = tty->disc_data;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
901
  	if (c == ECHO_OP_START) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
902
903
  		add_echo_byte(ECHO_OP_START, ldata);
  		add_echo_byte(ECHO_OP_START, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
904
  	} else {
62b263585   Joe Peterson   n_tty: move echoc...
905
  		if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
57c941212   Jiri Slaby   TTY: n_tty, propa...
906
907
  			add_echo_byte(ECHO_OP_START, ldata);
  		add_echo_byte(c, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
908
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
  }
17b820606   Alan Cox   tty: Minor tidyup...
910
  /**
a88a69c91   Joe Peterson   n_tty: Fix loss o...
911
   *	finish_erasing		-	complete erase
57c941212   Jiri Slaby   TTY: n_tty, propa...
912
   *	@ldata: n_tty data
17b820606   Alan Cox   tty: Minor tidyup...
913
   */
a88a69c91   Joe Peterson   n_tty: Fix loss o...
914

57c941212   Jiri Slaby   TTY: n_tty, propa...
915
  static inline void finish_erasing(struct n_tty_data *ldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
917
  	if (ldata->erasing) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
918
  		echo_char_raw('/', ldata);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
919
  		ldata->erasing = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
922
923
924
925
926
927
  	}
  }
  
  /**
   *	eraser		-	handle erase function
   *	@c: character input
   *	@tty: terminal device
   *
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
928
   *	Perform erase and necessary output when an erase character is
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
   *	present in the stream from the driver layer. Handles the complexities
   *	of UTF-8 multibyte symbols.
17b820606   Alan Cox   tty: Minor tidyup...
931
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
932
933
   *	n_tty_receive_buf()/producer path:
   *		caller holds non-exclusive termios_rwsem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
   */
4edf1827e   Alan Cox   n_tty: clean up o...
935

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
  static void eraser(unsigned char c, struct tty_struct *tty)
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
938
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  	enum { ERASE, WERASE, KILL } kill_type;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
940
941
942
  	size_t head;
  	size_t cnt;
  	int seen_alnums;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943

ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
944
  	if (ldata->read_head == ldata->canon_head) {
7e94b1d9b   Joe Peterson   n_tty: Output bel...
945
  		/* process_output('\a', tty); */ /* what do you think? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
949
950
951
952
953
  		return;
  	}
  	if (c == ERASE_CHAR(tty))
  		kill_type = ERASE;
  	else if (c == WERASE_CHAR(tty))
  		kill_type = WERASE;
  	else {
  		if (!L_ECHO(tty)) {
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
954
  			ldata->read_head = ldata->canon_head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
956
957
  			return;
  		}
  		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
958
  			ldata->read_head = ldata->canon_head;
57c941212   Jiri Slaby   TTY: n_tty, propa...
959
  			finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
  			echo_char(KILL_CHAR(tty), tty);
  			/* Add a newline if ECHOK is on and ECHOKE is off. */
  			if (L_ECHOK(tty))
57c941212   Jiri Slaby   TTY: n_tty, propa...
963
964
  				echo_char_raw('
  ', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
967
968
969
970
  			return;
  		}
  		kill_type = KILL;
  	}
  
  	seen_alnums = 0;
3d63b7e4a   Tetsuo Handa   n_tty: Fix stall ...
971
  	while (MASK(ldata->read_head) != MASK(ldata->canon_head)) {
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
972
  		head = ldata->read_head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973
974
975
  
  		/* erase a single possibly multibyte character */
  		do {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
976
977
  			head--;
  			c = read_buf(ldata, head);
3d63b7e4a   Tetsuo Handa   n_tty: Fix stall ...
978
979
  		} while (is_continuation(c, tty) &&
  			 MASK(head) != MASK(ldata->canon_head));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
981
982
983
984
985
986
987
988
989
990
991
  
  		/* do not partially erase */
  		if (is_continuation(c, tty))
  			break;
  
  		if (kill_type == WERASE) {
  			/* Equivalent to BSD's ALTWERASE. */
  			if (isalnum(c) || c == '_')
  				seen_alnums++;
  			else if (seen_alnums)
  				break;
  		}
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
992
  		cnt = ldata->read_head - head;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
993
  		ldata->read_head = head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
995
  		if (L_ECHO(tty)) {
  			if (L_ECHOPRT(tty)) {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
996
  				if (!ldata->erasing) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
997
  					echo_char_raw('\\', ldata);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
998
  					ldata->erasing = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
1002
  				}
  				/* if cnt > 1, output a multi-byte character */
  				echo_char(c, tty);
  				while (--cnt > 0) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1003
1004
  					head++;
  					echo_char_raw(read_buf(ldata, head), ldata);
57c941212   Jiri Slaby   TTY: n_tty, propa...
1005
  					echo_move_back_col(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
1009
  				}
  			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
  				echo_char(ERASE_CHAR(tty), tty);
  			} else if (c == '\t') {
a88a69c91   Joe Peterson   n_tty: Fix loss o...
1010
1011
  				unsigned int num_chars = 0;
  				int after_tab = 0;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1012
  				size_t tail = ldata->read_head;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
1013
1014
1015
1016
1017
1018
1019
1020
  
  				/*
  				 * Count the columns used for characters
  				 * since the start of input or after a
  				 * previous tab.
  				 * This info is used to go back the correct
  				 * number of columns.
  				 */
3d63b7e4a   Tetsuo Handa   n_tty: Fix stall ...
1021
  				while (MASK(tail) != MASK(ldata->canon_head)) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1022
1023
  					tail--;
  					c = read_buf(ldata, tail);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
1024
1025
1026
  					if (c == '\t') {
  						after_tab = 1;
  						break;
300a6204b   Alan Cox   n_tty: clean up c...
1027
  					} else if (iscntrl(c)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
  						if (L_ECHOCTL(tty))
a88a69c91   Joe Peterson   n_tty: Fix loss o...
1029
1030
1031
1032
  							num_chars += 2;
  					} else if (!is_continuation(c, tty)) {
  						num_chars++;
  					}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
  				}
57c941212   Jiri Slaby   TTY: n_tty, propa...
1034
  				echo_erase_tab(num_chars, after_tab, ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
1036
  			} else {
  				if (iscntrl(c) && L_ECHOCTL(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1037
1038
1039
  					echo_char_raw('\b', ldata);
  					echo_char_raw(' ', ldata);
  					echo_char_raw('\b', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
1041
  				}
  				if (!iscntrl(c) || L_ECHOCTL(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1042
1043
1044
  					echo_char_raw('\b', ldata);
  					echo_char_raw(' ', ldata);
  					echo_char_raw('\b', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
1047
1048
1049
1050
  				}
  			}
  		}
  		if (kill_type == ERASE)
  			break;
  	}
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
1051
  	if (ldata->read_head == ldata->canon_head && L_ECHO(tty))
57c941212   Jiri Slaby   TTY: n_tty, propa...
1052
  		finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
1054
1055
1056
1057
1058
  }
  
  /**
   *	isig		-	handle the ISIG optio
   *	@sig: signal
   *	@tty: terminal
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
   *
8c985d18b   Peter Hurley   n_tty: Fix unsafe...
1060
1061
   *	Called when a signal is being sent due to terminal input.
   *	Called from the driver receive_buf path so serialized.
17b820606   Alan Cox   tty: Minor tidyup...
1062
   *
d2b6f4477   Peter Hurley   n_tty: Fix signal...
1063
1064
1065
1066
   *	Performs input and output flush if !NOFLSH. In this context, the echo
   *	buffer is 'output'. The signal is processed first to alert any current
   *	readers or writers to discontinue and exit their i/o loops.
   *
8c985d18b   Peter Hurley   n_tty: Fix unsafe...
1067
   *	Locking: ctrl_lock
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1068
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1069

3b19e0322   Peter Hurley   n_tty: signal and...
1070
  static void __isig(int sig, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071
  {
8c985d18b   Peter Hurley   n_tty: Fix unsafe...
1072
1073
1074
1075
  	struct pid *tty_pgrp = tty_get_pgrp(tty);
  	if (tty_pgrp) {
  		kill_pgrp(tty_pgrp, sig, 1);
  		put_pid(tty_pgrp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  	}
3b19e0322   Peter Hurley   n_tty: signal and...
1077
  }
d2b6f4477   Peter Hurley   n_tty: Fix signal...
1078

3b19e0322   Peter Hurley   n_tty: signal and...
1079
1080
1081
1082
1083
1084
1085
1086
1087
  static void isig(int sig, struct tty_struct *tty)
  {
  	struct n_tty_data *ldata = tty->disc_data;
  
  	if (L_NOFLSH(tty)) {
  		/* signal only */
  		__isig(sig, tty);
  
  	} else { /* signal and flush */
d2b6f4477   Peter Hurley   n_tty: Fix signal...
1088
1089
  		up_read(&tty->termios_rwsem);
  		down_write(&tty->termios_rwsem);
3b19e0322   Peter Hurley   n_tty: signal and...
1090
  		__isig(sig, tty);
d2b6f4477   Peter Hurley   n_tty: Fix signal...
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
  		/* clear echo buffer */
  		mutex_lock(&ldata->output_lock);
  		ldata->echo_head = ldata->echo_tail = 0;
  		ldata->echo_mark = ldata->echo_commit = 0;
  		mutex_unlock(&ldata->output_lock);
  
  		/* clear output buffer */
  		tty_driver_flush_buffer(tty);
  
  		/* clear input buffer */
  		reset_buffer_flags(tty->disc_data);
  
  		/* notify pty master of flush */
  		if (tty->link)
  			n_tty_packet_mode_flush(tty);
  
  		up_write(&tty->termios_rwsem);
  		down_read(&tty->termios_rwsem);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
1111
1112
1113
1114
1115
1116
1117
1118
  }
  
  /**
   *	n_tty_receive_break	-	handle break
   *	@tty: terminal
   *
   *	An RS232 break event has been hit in the incoming bitstream. This
   *	can cause a variety of events depending upon the termios settings.
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1119
1120
   *	n_tty_receive_buf()/producer path:
   *		caller holds non-exclusive termios_rwsem
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1121
1122
   *
   *	Note: may get exclusive termios_rwsem if flushing input buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1124

4b293492a   Peter Hurley   n_tty: Un-inline ...
1125
  static void n_tty_receive_break(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1127
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
1129
1130
  	if (I_IGNBRK(tty))
  		return;
  	if (I_BRKINT(tty)) {
8c985d18b   Peter Hurley   n_tty: Fix unsafe...
1131
  		isig(SIGINT, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
1134
  		return;
  	}
  	if (I_PARMRK(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1135
1136
  		put_tty_queue('\377', ldata);
  		put_tty_queue('\0', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
  	}
57c941212   Jiri Slaby   TTY: n_tty, propa...
1138
  	put_tty_queue('\0', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
  }
  
  /**
   *	n_tty_receive_overrun	-	handle overrun reporting
   *	@tty: terminal
   *
   *	Data arrived faster than we could process it. While the tty
   *	driver has flagged this the bits that were missed are gone
   *	forever.
   *
   *	Called from the receive_buf path so single threaded. Does not
   *	need locking as num_overrun and overrun_time are function
   *	private.
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1153

4b293492a   Peter Hurley   n_tty: Un-inline ...
1154
  static void n_tty_receive_overrun(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1156
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157

53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1158
1159
1160
  	ldata->num_overrun++;
  	if (time_after(jiffies, ldata->overrun_time + HZ) ||
  			time_after(ldata->overrun_time, jiffies)) {
339f36ba1   Peter Hurley   tty: Define tty_*...
1161
1162
  		tty_warn(tty, "%d input overrun(s)
  ", ldata->num_overrun);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1163
1164
  		ldata->overrun_time = jiffies;
  		ldata->num_overrun = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
1168
1169
1170
1171
1172
1173
  	}
  }
  
  /**
   *	n_tty_receive_parity_error	-	error notifier
   *	@tty: terminal device
   *	@c: character
   *
   *	Process a parity error and queue the right data to indicate
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1174
1175
1176
1177
   *	the error case if necessary.
   *
   *	n_tty_receive_buf()/producer path:
   *		caller holds non-exclusive termios_rwsem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
   */
4b293492a   Peter Hurley   n_tty: Un-inline ...
1179
  static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1181
  	struct n_tty_data *ldata = tty->disc_data;
66528f906   Peter Hurley   tty: Correct INPC...
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
  	if (I_INPCK(tty)) {
  		if (I_IGNPAR(tty))
  			return;
  		if (I_PARMRK(tty)) {
  			put_tty_queue('\377', ldata);
  			put_tty_queue('\0', ldata);
  			put_tty_queue(c, ldata);
  		} else
  			put_tty_queue('\0', ldata);
  	} else
57c941212   Jiri Slaby   TTY: n_tty, propa...
1192
  		put_tty_queue(c, ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
  }
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1194
1195
1196
  static void
  n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
  {
d2b6f4477   Peter Hurley   n_tty: Fix signal...
1197
  	isig(signal, tty);
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1198
1199
1200
1201
1202
  	if (I_IXON(tty))
  		start_tty(tty);
  	if (L_ECHO(tty)) {
  		echo_char(c, tty);
  		commit_echoes(tty);
e2613be50   Peter Hurley   n_tty: Fix stale ...
1203
1204
  	} else
  		process_echoes(tty);
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1205
1206
  	return;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
1208
1209
1210
1211
1212
  /**
   *	n_tty_receive_char	-	perform processing
   *	@tty: terminal device
   *	@c: character
   *
   *	Process an individual character of input received from the driver.
4edf1827e   Alan Cox   n_tty: clean up o...
1213
   *	This is serialized with respect to itself by the rules for the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
   *	driver above.
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1215
1216
1217
1218
   *
   *	n_tty_receive_buf()/producer path:
   *		caller holds non-exclusive termios_rwsem
   *		publishes canon_head if canonical mode is active
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1219
1220
   *
   *	Returns 1 if LNEXT was received, else returns 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
   */
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1222
  static int
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1223
  n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1225
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
1228
1229
  	if (I_IXON(tty)) {
  		if (c == START_CHAR(tty)) {
  			start_tty(tty);
e2613be50   Peter Hurley   n_tty: Fix stale ...
1230
  			process_echoes(tty);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1231
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
1233
1234
  		}
  		if (c == STOP_CHAR(tty)) {
  			stop_tty(tty);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1235
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
1237
  		}
  	}
575537b32   Joe Peterson   Resume TTY on SUS...
1238

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
  	if (L_ISIG(tty)) {
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1240
1241
  		if (c == INTR_CHAR(tty)) {
  			n_tty_receive_signal_char(tty, SIGINT, c);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1242
  			return 0;
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1243
1244
  		} else if (c == QUIT_CHAR(tty)) {
  			n_tty_receive_signal_char(tty, SIGQUIT, c);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1245
  			return 0;
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1246
1247
  		} else if (c == SUSP_CHAR(tty)) {
  			n_tty_receive_signal_char(tty, SIGTSTP, c);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1248
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
1250
  		}
  	}
575537b32   Joe Peterson   Resume TTY on SUS...
1251

855df3c08   Peter Hurley   n_tty: Eliminate ...
1252
1253
1254
1255
  	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
  		start_tty(tty);
  		process_echoes(tty);
  	}
575537b32   Joe Peterson   Resume TTY on SUS...
1256
1257
  	if (c == '\r') {
  		if (I_IGNCR(tty))
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1258
  			return 0;
575537b32   Joe Peterson   Resume TTY on SUS...
1259
1260
1261
1262
1263
1264
  		if (I_ICRNL(tty))
  			c = '
  ';
  	} else if (c == '
  ' && I_INLCR(tty))
  		c = '\r';
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1265
  	if (ldata->icanon) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1266
1267
1268
  		if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
  		    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
  			eraser(c, tty);
17bd79074   Peter Hurley   n_tty: Remove ech...
1269
  			commit_echoes(tty);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1270
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
1272
  		}
  		if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1273
  			ldata->lnext = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  			if (L_ECHO(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1275
  				finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
  				if (L_ECHOCTL(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1277
1278
  					echo_char_raw('^', ldata);
  					echo_char_raw('\b', ldata);
17bd79074   Peter Hurley   n_tty: Remove ech...
1279
  					commit_echoes(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
1281
  				}
  			}
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1282
  			return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
  		}
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1284
  		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1285
  			size_t tail = ldata->canon_head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1286

57c941212   Jiri Slaby   TTY: n_tty, propa...
1287
  			finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
  			echo_char(c, tty);
57c941212   Jiri Slaby   TTY: n_tty, propa...
1289
1290
  			echo_char_raw('
  ', ldata);
3d63b7e4a   Tetsuo Handa   n_tty: Fix stall ...
1291
  			while (MASK(tail) != MASK(ldata->read_head)) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1292
1293
  				echo_char(read_buf(ldata, tail), tty);
  				tail++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  			}
17bd79074   Peter Hurley   n_tty: Remove ech...
1295
  			commit_echoes(tty);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1296
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
1298
1299
  		}
  		if (c == '
  ') {
acc71bbad   Joe Peterson   n_tty: Fix hanfli...
1300
  			if (L_ECHO(tty) || L_ECHONL(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1301
1302
  				echo_char_raw('
  ', ldata);
17bd79074   Peter Hurley   n_tty: Remove ech...
1303
  				commit_echoes(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
1305
1306
1307
  			}
  			goto handle_newline;
  		}
  		if (c == EOF_CHAR(tty)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
1310
1311
1312
1313
1314
1315
1316
  			c = __DISABLED_CHAR;
  			goto handle_newline;
  		}
  		if ((c == EOL_CHAR(tty)) ||
  		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
  			/*
  			 * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
  			 */
  			if (L_ECHO(tty)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
  				/* Record the column of first canon char. */
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
1318
  				if (ldata->canon_head == ldata->read_head)
57c941212   Jiri Slaby   TTY: n_tty, propa...
1319
  					echo_set_canon_col(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
  				echo_char(c, tty);
17bd79074   Peter Hurley   n_tty: Remove ech...
1321
  				commit_echoes(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322
1323
1324
1325
1326
  			}
  			/*
  			 * XXX does PARMRK doubling happen for
  			 * EOL_CHAR and EOL2_CHAR?
  			 */
001ba9237   Peter Hurley   n_tty: Refactor P...
1327
  			if (c == (unsigned char) '\377' && I_PARMRK(tty))
57c941212   Jiri Slaby   TTY: n_tty, propa...
1328
  				put_tty_queue(c, ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329

4edf1827e   Alan Cox   n_tty: clean up o...
1330
  handle_newline:
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1331
  			set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags);
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1332
  			put_tty_queue(c, ldata);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1333
  			smp_store_release(&ldata->canon_head, ldata->read_head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
  			kill_fasync(&tty->fasync, SIGIO, POLL_IN);
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1335
  			wake_up_interruptible_poll(&tty->read_wait, EPOLLIN);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1336
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
1338
  		}
  	}
4edf1827e   Alan Cox   n_tty: clean up o...
1339

acc71bbad   Joe Peterson   n_tty: Fix hanfli...
1340
  	if (L_ECHO(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1341
  		finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
1343
  		if (c == '
  ')
57c941212   Jiri Slaby   TTY: n_tty, propa...
1344
1345
  			echo_char_raw('
  ', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
1347
  		else {
  			/* Record the column of first canon char. */
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
1348
  			if (ldata->canon_head == ldata->read_head)
57c941212   Jiri Slaby   TTY: n_tty, propa...
1349
  				echo_set_canon_col(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1350
1351
  			echo_char(c, tty);
  		}
17bd79074   Peter Hurley   n_tty: Remove ech...
1352
  		commit_echoes(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
  	}
001ba9237   Peter Hurley   n_tty: Refactor P...
1354
1355
  	/* PARMRK doubling check */
  	if (c == (unsigned char) '\377' && I_PARMRK(tty))
57c941212   Jiri Slaby   TTY: n_tty, propa...
1356
  		put_tty_queue(c, ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357

57c941212   Jiri Slaby   TTY: n_tty, propa...
1358
  	put_tty_queue(c, ldata);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1359
  	return 0;
4edf1827e   Alan Cox   n_tty: clean up o...
1360
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361

e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1362
1363
  static inline void
  n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1364
1365
  {
  	struct n_tty_data *ldata = tty->disc_data;
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1366

e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
  	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
  		start_tty(tty);
  		process_echoes(tty);
  	}
  	if (L_ECHO(tty)) {
  		finish_erasing(ldata);
  		/* Record the column of first canon char. */
  		if (ldata->canon_head == ldata->read_head)
  			echo_set_canon_col(ldata);
  		echo_char(c, tty);
  		commit_echoes(tty);
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1378
  	}
001ba9237   Peter Hurley   n_tty: Refactor P...
1379
1380
  	/* PARMRK doubling check */
  	if (c == (unsigned char) '\377' && I_PARMRK(tty))
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1381
1382
1383
  		put_tty_queue(c, ldata);
  	put_tty_queue(c, ldata);
  }
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1384

eb3e4668b   Peter Hurley   n_tty: Un-inline ...
1385
  static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1386
1387
  {
  	n_tty_receive_char_inline(tty, c);
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1388
  }
ad0cc7baf   Peter Hurley   n_tty: Factor tty...
1389
  static inline void
7de971b05   Peter Hurley   n_tty: Factor PAR...
1390
1391
1392
  n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
  {
  	struct n_tty_data *ldata = tty->disc_data;
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1393
1394
1395
  	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
  		start_tty(tty);
  		process_echoes(tty);
7de971b05   Peter Hurley   n_tty: Factor PAR...
1396
  	}
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1397
1398
1399
1400
1401
1402
1403
1404
1405
  	if (L_ECHO(tty)) {
  		finish_erasing(ldata);
  		/* Record the column of first canon char. */
  		if (ldata->canon_head == ldata->read_head)
  			echo_set_canon_col(ldata);
  		echo_char(c, tty);
  		commit_echoes(tty);
  	}
  	put_tty_queue(c, ldata);
7de971b05   Peter Hurley   n_tty: Factor PAR...
1406
  }
8dc4b25d2   Peter Hurley   n_tty: Un-inline ...
1407
  static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
ad0cc7baf   Peter Hurley   n_tty: Factor tty...
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
  {
  	if (I_ISTRIP(tty))
  		c &= 0x7f;
  	if (I_IUCLC(tty) && L_IEXTEN(tty))
  		c = tolower(c);
  
  	if (I_IXON(tty)) {
  		if (c == STOP_CHAR(tty))
  			stop_tty(tty);
  		else if (c == START_CHAR(tty) ||
  			 (tty->stopped && !tty->flow_stopped && I_IXANY(tty) &&
  			  c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
  			  c != SUSP_CHAR(tty))) {
  			start_tty(tty);
  			process_echoes(tty);
  		}
  	}
  }
d2f8d7abd   Peter Hurley   n_tty: Factor fla...
1426
1427
1428
  static void
  n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
  {
d2f8d7abd   Peter Hurley   n_tty: Factor fla...
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
  	switch (flag) {
  	case TTY_BREAK:
  		n_tty_receive_break(tty);
  		break;
  	case TTY_PARITY:
  	case TTY_FRAME:
  		n_tty_receive_parity_error(tty, c);
  		break;
  	case TTY_OVERRUN:
  		n_tty_receive_overrun(tty);
  		break;
  	default:
339f36ba1   Peter Hurley   tty: Define tty_*...
1441
1442
  		tty_err(tty, "unknown flag %d
  ", flag);
d2f8d7abd   Peter Hurley   n_tty: Factor fla...
1443
1444
1445
  		break;
  	}
  }
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
  static void
  n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
  {
  	struct n_tty_data *ldata = tty->disc_data;
  
  	ldata->lnext = 0;
  	if (likely(flag == TTY_NORMAL)) {
  		if (I_ISTRIP(tty))
  			c &= 0x7f;
  		if (I_IUCLC(tty) && L_IEXTEN(tty))
  			c = tolower(c);
  		n_tty_receive_char(tty, c);
  	} else
  		n_tty_receive_char_flagged(tty, c, flag);
  }
4a23a4df5   Peter Hurley   n_tty: Factor 're...
1461
1462
1463
1464
1465
1466
1467
1468
  static void
  n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
  			   char *fp, int count)
  {
  	struct n_tty_data *ldata = tty->disc_data;
  	size_t n, head;
  
  	head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1469
  	n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
4a23a4df5   Peter Hurley   n_tty: Factor 're...
1470
1471
1472
1473
1474
1475
  	memcpy(read_buf_addr(ldata, head), cp, n);
  	ldata->read_head += n;
  	cp += n;
  	count -= n;
  
  	head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1476
  	n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
4a23a4df5   Peter Hurley   n_tty: Factor 're...
1477
1478
1479
  	memcpy(read_buf_addr(ldata, head), cp, n);
  	ldata->read_head += n;
  }
554117bdc   Peter Hurley   n_tty: Factor raw...
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
  static void
  n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp,
  		      char *fp, int count)
  {
  	struct n_tty_data *ldata = tty->disc_data;
  	char flag = TTY_NORMAL;
  
  	while (count--) {
  		if (fp)
  			flag = *fp++;
  		if (likely(flag == TTY_NORMAL))
  			put_tty_queue(*cp++, ldata);
  		else
  			n_tty_receive_char_flagged(tty, *cp++, flag);
  	}
  }
ad0cc7baf   Peter Hurley   n_tty: Factor tty...
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
  static void
  n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
  			  char *fp, int count)
  {
  	char flag = TTY_NORMAL;
  
  	while (count--) {
  		if (fp)
  			flag = *fp++;
  		if (likely(flag == TTY_NORMAL))
  			n_tty_receive_char_closing(tty, *cp++);
ad0cc7baf   Peter Hurley   n_tty: Factor tty...
1507
1508
  	}
  }
7d88d637a   Peter Hurley   n_tty: Factor sta...
1509
1510
  static void
  n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp,
6baad0086   Peter Hurley   n_tty: Factor IST...
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
  			  char *fp, int count)
  {
  	struct n_tty_data *ldata = tty->disc_data;
  	char flag = TTY_NORMAL;
  
  	while (count--) {
  		if (fp)
  			flag = *fp++;
  		if (likely(flag == TTY_NORMAL)) {
  			unsigned char c = *cp++;
  
  			if (I_ISTRIP(tty))
  				c &= 0x7f;
  			if (I_IUCLC(tty) && L_IEXTEN(tty))
  				c = tolower(c);
  			if (L_EXTPROC(tty)) {
  				put_tty_queue(c, ldata);
  				continue;
  			}
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1530
1531
1532
1533
1534
1535
1536
1537
  			if (!test_bit(c, ldata->char_map))
  				n_tty_receive_char_inline(tty, c);
  			else if (n_tty_receive_char_special(tty, c) && count) {
  				if (fp)
  					flag = *fp++;
  				n_tty_receive_char_lnext(tty, *cp++, flag);
  				count--;
  			}
6baad0086   Peter Hurley   n_tty: Factor IST...
1538
1539
1540
1541
1542
1543
1544
1545
  		} else
  			n_tty_receive_char_flagged(tty, *cp++, flag);
  	}
  }
  
  static void
  n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp,
  		       char *fp, int count)
7d88d637a   Peter Hurley   n_tty: Factor sta...
1546
  {
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1547
  	struct n_tty_data *ldata = tty->disc_data;
7d88d637a   Peter Hurley   n_tty: Factor sta...
1548
1549
1550
1551
1552
  	char flag = TTY_NORMAL;
  
  	while (count--) {
  		if (fp)
  			flag = *fp++;
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
  		if (likely(flag == TTY_NORMAL)) {
  			unsigned char c = *cp++;
  
  			if (!test_bit(c, ldata->char_map))
  				n_tty_receive_char_fast(tty, c);
  			else if (n_tty_receive_char_special(tty, c) && count) {
  				if (fp)
  					flag = *fp++;
  				n_tty_receive_char_lnext(tty, *cp++, flag);
  				count--;
  			}
  		} else
7d88d637a   Peter Hurley   n_tty: Factor sta...
1565
1566
1567
  			n_tty_receive_char_flagged(tty, *cp++, flag);
  	}
  }
24a89d1cb   Peter Hurley   tty: Make ldisc i...
1568
1569
  static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
  			  char *fp, int count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1571
  	struct n_tty_data *ldata = tty->disc_data;
a1dd30e9b   Peter Hurley   n_tty: Special ca...
1572
  	bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1573

4a23a4df5   Peter Hurley   n_tty: Factor 're...
1574
1575
  	if (ldata->real_raw)
  		n_tty_receive_buf_real_raw(tty, cp, fp, count);
a1dd30e9b   Peter Hurley   n_tty: Special ca...
1576
  	else if (ldata->raw || (L_EXTPROC(tty) && !preops))
554117bdc   Peter Hurley   n_tty: Factor raw...
1577
  		n_tty_receive_buf_raw(tty, cp, fp, count);
ad0cc7baf   Peter Hurley   n_tty: Factor tty...
1578
1579
  	else if (tty->closing && !L_EXTPROC(tty))
  		n_tty_receive_buf_closing(tty, cp, fp, count);
4a23a4df5   Peter Hurley   n_tty: Factor 're...
1580
  	else {
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1581
1582
1583
1584
1585
1586
1587
1588
  		if (ldata->lnext) {
  			char flag = TTY_NORMAL;
  
  			if (fp)
  				flag = *fp++;
  			n_tty_receive_char_lnext(tty, *cp++, flag);
  			count--;
  		}
7de971b05   Peter Hurley   n_tty: Factor PAR...
1589
  		if (!preops && !I_PARMRK(tty))
6baad0086   Peter Hurley   n_tty: Factor IST...
1590
1591
1592
  			n_tty_receive_buf_fast(tty, cp, fp, count);
  		else
  			n_tty_receive_buf_standard(tty, cp, fp, count);
cbfd0340a   Peter Hurley   n_tty: Process ec...
1593
1594
  
  		flush_echoes(tty);
f34d7a5b7   Alan Cox   tty: The big oper...
1595
1596
  		if (tty->ops->flush_chars)
  			tty->ops->flush_chars(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
  	}
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1598
1599
1600
1601
1602
  	if (ldata->icanon && !L_EXTPROC(tty))
  		return;
  
  	/* publish read_head to consumer */
  	smp_store_release(&ldata->commit_head, ldata->read_head);
33d713633   Peter Hurley   n_tty: Always wak...
1603
  	if (read_cnt(ldata)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
  		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1605
  		wake_up_interruptible_poll(&tty->read_wait, EPOLLIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1607
  }
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
  /**
   *	n_tty_receive_buf_common	-	process input
   *	@tty: device to receive input
   *	@cp: input chars
   *	@fp: flags for each char (if NULL, all chars are TTY_NORMAL)
   *	@count: number of input chars in @cp
   *
   *	Called by the terminal driver when a block of characters has
   *	been received. This function must be called from soft contexts
   *	not from interrupt context. The driver is responsible for making
   *	calls one at a time and in order (or using flush_to_ldisc)
   *
   *	Returns the # of input chars from @cp which were processed.
   *
   *	In canonical mode, the maximum line length is 4096 chars (including
   *	the line termination char); lines longer than 4096 chars are
   *	truncated. After 4095 chars, input data is still processed but
   *	not stored. Overflow processing ensures the tty can always
   *	receive more input until at least one line can be read.
   *
   *	In non-canonical mode, the read buffer will only accept 4095 chars;
   *	this provides the necessary space for a newline char if the input
   *	mode is switched to canonical.
   *
   *	Note it is possible for the read buffer to _contain_ 4096 chars
   *	in non-canonical mode: the read buffer could already contain the
   *	maximum canon line of 4096 chars when the mode is switched to
   *	non-canonical.
   *
   *	n_tty_receive_buf()/producer path:
   *		claims non-exclusive termios_rwsem
   *		publishes commit_head or canon_head
   */
5c32d1237   Peter Hurley   n_tty: Merge .rec...
1641
1642
1643
  static int
  n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
  			 char *fp, int count, int flow)
24a89d1cb   Peter Hurley   tty: Make ldisc i...
1644
1645
  {
  	struct n_tty_data *ldata = tty->disc_data;
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1646
  	int room, n, rcvd = 0, overflow;
24a89d1cb   Peter Hurley   tty: Make ldisc i...
1647

9356b535f   Peter Hurley   n_tty: Access ter...
1648
  	down_read(&tty->termios_rwsem);
c96cf923a   Dmitry Safonov   tty: Don't block ...
1649
  	do {
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1650
  		/*
06c49f9fa   Peter Hurley   n_tty: Fix PARMRK...
1651
1652
  		 * When PARMRK is set, each input char may take up to 3 chars
  		 * in the read buf; reduce the buffer space avail by 3x
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
  		 *
  		 * If we are doing input canonicalization, and there are no
  		 * pending newlines, let characters through without limit, so
  		 * that erase characters will be handled.  Other excess
  		 * characters will be beeped.
  		 *
  		 * paired with store in *_copy_from_read_buf() -- guarantees
  		 * the consumer has loaded the data in read_buf up to the new
  		 * read_tail (so this producer will not overwrite unread data)
  		 */
  		size_t tail = smp_load_acquire(&ldata->read_tail);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1664

fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1665
  		room = N_TTY_BUF_SIZE - (ldata->read_head - tail);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1666
  		if (I_PARMRK(tty))
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
  			room = (room + 2) / 3;
  		room--;
  		if (room <= 0) {
  			overflow = ldata->icanon && ldata->canon_head == tail;
  			if (overflow && room < 0)
  				ldata->read_head--;
  			room = overflow;
  			ldata->no_room = flow && !room;
  		} else
  			overflow = 0;
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1677

19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1678
  		n = min(count, room);
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1679
  		if (!n)
19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1680
  			break;
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1681
1682
1683
1684
  
  		/* ignore parity errors if handling overflow */
  		if (!overflow || !fp || *fp != TTY_PARITY)
  			__receive_buf(tty, cp, fp, n);
19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1685
1686
1687
1688
1689
  		cp += n;
  		if (fp)
  			fp += n;
  		count -= n;
  		rcvd += n;
c96cf923a   Dmitry Safonov   tty: Don't block ...
1690
  	} while (!test_bit(TTY_LDISC_CHANGING, &tty->flags));
24a89d1cb   Peter Hurley   tty: Make ldisc i...
1691

19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1692
  	tty->receive_room = room;
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
  
  	/* Unthrottle if handling overflow on pty */
  	if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
  		if (overflow) {
  			tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
  			tty_unthrottle_safe(tty);
  			__tty_set_flow_change(tty, 0);
  		}
  	} else
  		n_tty_check_throttle(tty);
9356b535f   Peter Hurley   n_tty: Access ter...
1703
  	up_read(&tty->termios_rwsem);
19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1704
  	return rcvd;
24a89d1cb   Peter Hurley   tty: Make ldisc i...
1705
  }
5c32d1237   Peter Hurley   n_tty: Merge .rec...
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
  static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
  			      char *fp, int count)
  {
  	n_tty_receive_buf_common(tty, cp, fp, count, 0);
  }
  
  static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
  			      char *fp, int count)
  {
  	return n_tty_receive_buf_common(tty, cp, fp, count, 1);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1717
1718
1719
1720
1721
1722
1723
  /**
   *	n_tty_set_termios	-	termios data changed
   *	@tty: terminal
   *	@old: previous data
   *
   *	Called by the tty layer when the user changes termios flags so
   *	that the line discipline can plan ahead. This function cannot sleep
4edf1827e   Alan Cox   n_tty: clean up o...
1724
   *	and is protected from re-entry by the tty layer. The user is
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1725
1726
   *	guaranteed that this function will not be re-entered or in progress
   *	when the ldisc is closed.
17b820606   Alan Cox   tty: Minor tidyup...
1727
   *
6a1c0680c   Peter Hurley   tty: Convert term...
1728
   *	Locking: Caller holds tty->termios_rwsem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1730
1731
  
  static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1732
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1733
  	struct n_tty_data *ldata = tty->disc_data;
47afa7a5a   Alan Cox   tty: some ICANON ...
1734

966031f34   Linus Torvalds   n_tty: fix EXTPRO...
1735
  	if (!old || (old->c_lflag ^ tty->termios.c_lflag) & (ICANON | EXTPROC)) {
3fe780b37   Jiri Slaby   TTY: move ldisc d...
1736
  		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
4d0ed1827   Peter Hurley   n_tty: Fix buffer...
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
  		ldata->line_start = ldata->read_tail;
  		if (!L_ICANON(tty) || !read_cnt(ldata)) {
  			ldata->canon_head = ldata->read_tail;
  			ldata->push = 0;
  		} else {
  			set_bit((ldata->read_head - 1) & (N_TTY_BUF_SIZE - 1),
  				ldata->read_flags);
  			ldata->canon_head = ldata->read_head;
  			ldata->push = 1;
  		}
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1747
  		ldata->commit_head = ldata->read_head;
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1748
  		ldata->erasing = 0;
6f9b028a8   Peter Hurley   n_tty: Reset lnex...
1749
  		ldata->lnext = 0;
47afa7a5a   Alan Cox   tty: some ICANON ...
1750
  	}
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1751
  	ldata->icanon = (L_ICANON(tty) != 0);
582f55907   Peter Hurley   tty: Remove TTY_H...
1752

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
1754
1755
1756
  	if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
  	    I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
  	    I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
  	    I_PARMRK(tty)) {
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1757
  		bitmap_zero(ldata->char_map, 256);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1758
1759
  
  		if (I_IGNCR(tty) || I_ICRNL(tty))
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1760
  			set_bit('\r', ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1761
  		if (I_INLCR(tty))
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1762
1763
  			set_bit('
  ', ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1764
1765
  
  		if (L_ICANON(tty)) {
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1766
1767
1768
1769
1770
1771
  			set_bit(ERASE_CHAR(tty), ldata->char_map);
  			set_bit(KILL_CHAR(tty), ldata->char_map);
  			set_bit(EOF_CHAR(tty), ldata->char_map);
  			set_bit('
  ', ldata->char_map);
  			set_bit(EOL_CHAR(tty), ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772
  			if (L_IEXTEN(tty)) {
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1773
1774
1775
  				set_bit(WERASE_CHAR(tty), ldata->char_map);
  				set_bit(LNEXT_CHAR(tty), ldata->char_map);
  				set_bit(EOL2_CHAR(tty), ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776
1777
  				if (L_ECHO(tty))
  					set_bit(REPRINT_CHAR(tty),
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1778
  						ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1779
1780
1781
  			}
  		}
  		if (I_IXON(tty)) {
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1782
1783
  			set_bit(START_CHAR(tty), ldata->char_map);
  			set_bit(STOP_CHAR(tty), ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
  		}
  		if (L_ISIG(tty)) {
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1786
1787
1788
  			set_bit(INTR_CHAR(tty), ldata->char_map);
  			set_bit(QUIT_CHAR(tty), ldata->char_map);
  			set_bit(SUSP_CHAR(tty), ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1789
  		}
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1790
  		clear_bit(__DISABLED_CHAR, ldata->char_map);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1791
1792
  		ldata->raw = 0;
  		ldata->real_raw = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1793
  	} else {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1794
  		ldata->raw = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1795
1796
1797
  		if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
  		    (I_IGNPAR(tty) || !I_INPCK(tty)) &&
  		    (tty->driver->flags & TTY_DRIVER_REAL_RAW))
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1798
  			ldata->real_raw = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1799
  		else
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1800
  			ldata->real_raw = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1801
  	}
dab73b4eb   Wang YanQing   TTY: Fix tty miss...
1802
1803
1804
1805
  	/*
  	 * Fix tty hang when I_IXON(tty) is cleared, but the tty
  	 * been stopped by STOP_CHAR(tty) before it.
  	 */
e2613be50   Peter Hurley   n_tty: Fix stale ...
1806
  	if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
dab73b4eb   Wang YanQing   TTY: Fix tty miss...
1807
  		start_tty(tty);
e2613be50   Peter Hurley   n_tty: Fix stale ...
1808
1809
  		process_echoes(tty);
  	}
dab73b4eb   Wang YanQing   TTY: Fix tty miss...
1810

f34d7a5b7   Alan Cox   tty: The big oper...
1811
  	/* The termios change make the tty ready for I/O */
e81107d4c   Kosuke Tatsukawa   tty: fix stall ca...
1812
1813
  	wake_up_interruptible(&tty->write_wait);
  	wake_up_interruptible(&tty->read_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814
1815
1816
1817
1818
1819
  }
  
  /**
   *	n_tty_close		-	close the ldisc for this tty
   *	@tty: device
   *
4edf1827e   Alan Cox   n_tty: clean up o...
1820
1821
   *	Called from the terminal layer when this line discipline is
   *	being shut down, either because of a close or becsuse of a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1822
1823
1824
   *	discipline change. The function will not be called while other
   *	ldisc methods are in progress.
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1825

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1826
1827
  static void n_tty_close(struct tty_struct *tty)
  {
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1828
  	struct n_tty_data *ldata = tty->disc_data;
79901317c   Peter Hurley   n_tty: Don't flus...
1829
1830
  	if (tty->link)
  		n_tty_packet_mode_flush(tty);
20bafb3d2   Peter Hurley   n_tty: Move buffe...
1831
  	vfree(ldata);
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1832
  	tty->disc_data = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1833
1834
1835
1836
1837
1838
  }
  
  /**
   *	n_tty_open		-	open an ldisc
   *	@tty: terminal to open
   *
4edf1827e   Alan Cox   n_tty: clean up o...
1839
   *	Called when this line discipline is being attached to the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840
1841
1842
1843
1844
1845
1846
   *	terminal device. Can sleep. Called serialized so that no
   *	other events will occur in parallel. No further open will occur
   *	until a close.
   */
  
  static int n_tty_open(struct tty_struct *tty)
  {
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1847
  	struct n_tty_data *ldata;
20bafb3d2   Peter Hurley   n_tty: Move buffe...
1848
  	/* Currently a malloc failure here can panic */
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
1849
  	ldata = vzalloc(sizeof(*ldata));
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1850
  	if (!ldata)
ebec3f8f5   Tetsuo Handa   n_tty: Access ech...
1851
  		return -ENOMEM;
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1852

53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1853
  	ldata->overrun_time = jiffies;
bddc7152f   Jiri Slaby   TTY: move ldisc d...
1854
1855
  	mutex_init(&ldata->atomic_read_lock);
  	mutex_init(&ldata->output_lock);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1856

70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1857
  	tty->disc_data = ldata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1858
  	tty->closing = 0;
b66f4fa50   Peter Hurley   n_tty: Fully init...
1859
1860
1861
1862
  	/* indicate buffer work may resume */
  	clear_bit(TTY_LDISC_HALTED, &tty->flags);
  	n_tty_set_termios(tty, NULL);
  	tty_unthrottle(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1863
1864
  	return 0;
  }
eafbe67f8   Peter Hurley   n_tty: Refactor i...
1865
  static inline int input_available_p(struct tty_struct *tty, int poll)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1866
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1867
  	struct n_tty_data *ldata = tty->disc_data;
a5934804a   Peter Hurley   n_tty: Fix poll()...
1868
  	int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1869

25e8d0ed7   Peter Hurley   n_tty: Simplify i...
1870
1871
1872
  	if (ldata->icanon && !L_EXTPROC(tty))
  		return ldata->canon_head != ldata->read_tail;
  	else
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1873
  		return ldata->commit_head - ldata->read_tail >= amt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1874
1875
1876
  }
  
  /**
bbd20759d   Thorsten Wißmann   drivers/tty: Remo...
1877
   *	copy_from_read_buf	-	copy read data directly
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
1879
1880
1881
   *	@tty: terminal device
   *	@b: user data
   *	@nr: size of data
   *
11a96d182   Alan Cox   tty: rename the r...
1882
   *	Helper function to speed up n_tty_read.  It is only called when
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1883
1884
1885
1886
1887
1888
   *	ICANON is off; it copies characters straight from the tty queue to
   *	user space directly.  It can be profitably called twice; once to
   *	drain the space from the tail pointer to the (physical) end of the
   *	buffer, and once to drain the space from the (physical) beginning of
   *	the buffer to head pointer.
   *
bddc7152f   Jiri Slaby   TTY: move ldisc d...
1889
   *	Called under the ldata->atomic_read_lock sem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1890
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1891
1892
1893
   *	n_tty_read()/consumer path:
   *		caller holds non-exclusive termios_rwsem
   *		read_tail published
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1894
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1895

33f0f88f1   Alan Cox   [PATCH] TTY layer...
1896
  static int copy_from_read_buf(struct tty_struct *tty,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1897
1898
1899
1900
  				      unsigned char __user **b,
  				      size_t *nr)
  
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1901
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1902
1903
  	int retval;
  	size_t n;
3fa10cc83   Jiri Slaby   TTY: n_tty, do no...
1904
  	bool is_eof;
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1905
  	size_t head = smp_load_acquire(&ldata->commit_head);
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1906
  	size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1907
1908
  
  	retval = 0;
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1909
  	n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1910
  	n = min(*nr, n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1911
  	if (n) {
b97b3d9fb   Greg Kroah-Hartman   tty: wipe buffer ...
1912
  		unsigned char *from = read_buf_addr(ldata, tail);
e661cf702   Peter Hurley   n_tty: Clarify co...
1913
  		retval = copy_to_user(*b, from, n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1914
  		n -= retval;
e661cf702   Peter Hurley   n_tty: Clarify co...
1915
  		is_eof = n == 1 && *from == EOF_CHAR(tty);
309426ae6   Peter Hurley   tty: audit: Remov...
1916
  		tty_audit_add_data(tty, from, n);
b97b3d9fb   Greg Kroah-Hartman   tty: wipe buffer ...
1917
  		zero_buffer(tty, from, n);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1918
  		smp_store_release(&ldata->read_tail, ldata->read_tail + n);
26df6d134   hyc@symas.com   tty: Add EXTPROC ...
1919
  		/* Turn single EOF into zero-length read */
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1920
1921
  		if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
  		    (head == ldata->read_tail))
3fa10cc83   Jiri Slaby   TTY: n_tty, do no...
1922
  			n = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1923
1924
1925
1926
1927
  		*b += n;
  		*nr -= n;
  	}
  	return retval;
  }
88bb0de38   Peter Hurley   n_tty: Factor can...
1928
  /**
32f13521c   Peter Hurley   n_tty: Line copy ...
1929
   *	canon_copy_from_read_buf	-	copy read data in canonical mode
88bb0de38   Peter Hurley   n_tty: Factor can...
1930
1931
1932
1933
1934
   *	@tty: terminal device
   *	@b: user data
   *	@nr: size of data
   *
   *	Helper function for n_tty_read.  It is only called when ICANON is on;
32f13521c   Peter Hurley   n_tty: Line copy ...
1935
1936
   *	it copies one line of input up to and including the line-delimiting
   *	character into the user-space buffer.
88bb0de38   Peter Hurley   n_tty: Factor can...
1937
   *
4d0ed1827   Peter Hurley   n_tty: Fix buffer...
1938
1939
1940
1941
1942
1943
   *	NB: When termios is changed from non-canonical to canonical mode and
   *	the read buffer contains data, n_tty_set_termios() simulates an EOF
   *	push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer.
   *	This causes data already processed as input to be immediately available
   *	as input although a newline has not been received.
   *
88bb0de38   Peter Hurley   n_tty: Factor can...
1944
   *	Called under the atomic_read_lock mutex
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1945
1946
1947
1948
   *
   *	n_tty_read()/consumer path:
   *		caller holds non-exclusive termios_rwsem
   *		read_tail published
88bb0de38   Peter Hurley   n_tty: Factor can...
1949
   */
32f13521c   Peter Hurley   n_tty: Line copy ...
1950
1951
1952
  static int canon_copy_from_read_buf(struct tty_struct *tty,
  				    unsigned char __user **b,
  				    size_t *nr)
88bb0de38   Peter Hurley   n_tty: Factor can...
1953
1954
  {
  	struct n_tty_data *ldata = tty->disc_data;
32f13521c   Peter Hurley   n_tty: Line copy ...
1955
  	size_t n, size, more, c;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1956
1957
1958
  	size_t eol;
  	size_t tail;
  	int ret, found = 0;
88bb0de38   Peter Hurley   n_tty: Factor can...
1959
1960
  
  	/* N.B. avoid overrun if nr == 0 */
ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
1961
  	if (!*nr)
32f13521c   Peter Hurley   n_tty: Line copy ...
1962
  		return 0;
88bb0de38   Peter Hurley   n_tty: Factor can...
1963

ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
1964
  	n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1965
  	tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
32f13521c   Peter Hurley   n_tty: Line copy ...
1966
  	size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1967
1968
  	n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu
  ",
32f13521c   Peter Hurley   n_tty: Line copy ...
1969
1970
1971
1972
1973
1974
1975
  		    __func__, *nr, tail, n, size);
  
  	eol = find_next_bit(ldata->read_flags, size, tail);
  	more = n - (size - tail);
  	if (eol == N_TTY_BUF_SIZE && more) {
  		/* scan wrapped without finding set bit */
  		eol = find_next_bit(ldata->read_flags, more, 0);
b985e9e36   Peter Hurley   n_tty: Reduce bra...
1976
1977
1978
  		found = eol != more;
  	} else
  		found = eol != size;
32f13521c   Peter Hurley   n_tty: Line copy ...
1979

c77569d2f   Peter Hurley   n_tty: Fix 4096-b...
1980
  	n = eol - tail;
da555db6b   Mark Tomlinson   n_tty: Fix calcul...
1981
1982
  	if (n > N_TTY_BUF_SIZE)
  		n += N_TTY_BUF_SIZE;
ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
1983
  	c = n + found;
32f13521c   Peter Hurley   n_tty: Line copy ...
1984

ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
1985
1986
1987
  	if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) {
  		c = min(*nr, c);
  		n = c;
40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
1988
  	}
32f13521c   Peter Hurley   n_tty: Line copy ...
1989

679e7c299   Peter Hurley   n_tty: Uninline t...
1990
1991
1992
  	n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu
  ",
  		    __func__, eol, found, n, c, tail, more);
32f13521c   Peter Hurley   n_tty: Line copy ...
1993

679e7c299   Peter Hurley   n_tty: Uninline t...
1994
  	ret = tty_copy_to_user(tty, *b, tail, n);
32f13521c   Peter Hurley   n_tty: Line copy ...
1995
1996
1997
1998
  	if (ret)
  		return -EFAULT;
  	*b += n;
  	*nr -= n;
a73d3d698   Peter Hurley   n_tty: Replace ca...
1999
  	if (found)
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
2000
  		clear_bit(eol, ldata->read_flags);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
2001
  	smp_store_release(&ldata->read_tail, ldata->read_tail + c);
88bb0de38   Peter Hurley   n_tty: Factor can...
2002

40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
2003
  	if (found) {
4d0ed1827   Peter Hurley   n_tty: Fix buffer...
2004
2005
2006
2007
  		if (!ldata->push)
  			ldata->line_start = ldata->read_tail;
  		else
  			ldata->push = 0;
b50819f43   Peter Hurley   tty: audit: Ignor...
2008
  		tty_audit_push();
40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
2009
  	}
ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
2010
  	return 0;
88bb0de38   Peter Hurley   n_tty: Factor can...
2011
  }
cc4191dc1   Al Viro   drivers/char/n_tt...
2012
  extern ssize_t redirected_tty_write(struct file *, const char __user *,
4edf1827e   Alan Cox   n_tty: clean up o...
2013
  							size_t, loff_t *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2014
2015
2016
2017
2018
2019
2020
  
  /**
   *	job_control		-	check job control
   *	@tty: tty
   *	@file: file handle
   *
   *	Perform job control management checks on this file/tty descriptor
4edf1827e   Alan Cox   n_tty: clean up o...
2021
   *	and if appropriate send any needed signals and return a negative
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2022
   *	error code if action should be taken.
04f378b19   Alan Cox   tty: BKL pushdown
2023
   *
01a5e440c   Peter Hurley   n_tty: Lock acces...
2024
2025
2026
   *	Locking: redirected write test is safe
   *		 current->signal->tty check is safe
   *		 ctrl_lock to safely reference tty->pgrp
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2027
   */
4edf1827e   Alan Cox   n_tty: clean up o...
2028

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029
2030
2031
2032
2033
2034
2035
  static int job_control(struct tty_struct *tty, struct file *file)
  {
  	/* Job control check -- must be done at start and after
  	   every sleep (POSIX.1 7.1.1.4). */
  	/* NOTE: not yet done after every sleep pending a thorough
  	   check of the logic of this change. -- jlc */
  	/* don't stop on /dev/console */
2812d9e9f   Peter Hurley   tty: Combine SIGT...
2036
  	if (file->f_op->write == redirected_tty_write)
01a5e440c   Peter Hurley   n_tty: Lock acces...
2037
  		return 0;
2812d9e9f   Peter Hurley   tty: Combine SIGT...
2038
  	return __tty_check_change(tty, SIGTTIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
  }
4edf1827e   Alan Cox   n_tty: clean up o...
2040

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2041
2042
  
  /**
11a96d182   Alan Cox   tty: rename the r...
2043
   *	n_tty_read		-	read function for tty
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
   *	@tty: tty device
   *	@file: file object
   *	@buf: userspace buffer pointer
   *	@nr: size of I/O
   *
   *	Perform reads for the line discipline. We are guaranteed that the
   *	line discipline will not be closed under us but we may get multiple
   *	parallel readers and must handle this ourselves. We may also get
   *	a hangup. Always called in user context, may sleep.
   *
   *	This code must be sure never to sleep through a hangup.
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
2055
2056
2057
2058
   *
   *	n_tty_read()/consumer path:
   *		claims non-exclusive termios_rwsem
   *		publishes read_tail
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2059
   */
4edf1827e   Alan Cox   n_tty: clean up o...
2060

11a96d182   Alan Cox   tty: rename the r...
2061
  static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2062
2063
  			 unsigned char __user *buf, size_t nr)
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
2064
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2065
  	unsigned char __user *b = buf;
97d9e28d1   Peter Zijlstra   sched, tty: Deal ...
2066
  	DEFINE_WAIT_FUNC(wait, woken_wake_function);
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2067
  	int c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2068
2069
  	int minimum, time;
  	ssize_t retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2070
  	long timeout;
04f378b19   Alan Cox   tty: BKL pushdown
2071
  	int packet;
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
2072
  	size_t tail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2074
  	c = job_control(tty, file);
4edf1827e   Alan Cox   n_tty: clean up o...
2075
  	if (c < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2076
  		return c;
4edf1827e   Alan Cox   n_tty: clean up o...
2077

aefceaf45   Peter Hurley   n_tty: Fix termio...
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
  	/*
  	 *	Internal serialization of reads.
  	 */
  	if (file->f_flags & O_NONBLOCK) {
  		if (!mutex_trylock(&ldata->atomic_read_lock))
  			return -EAGAIN;
  	} else {
  		if (mutex_lock_interruptible(&ldata->atomic_read_lock))
  			return -ERESTARTSYS;
  	}
9356b535f   Peter Hurley   n_tty: Access ter...
2088
  	down_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2089
2090
  	minimum = time = 0;
  	timeout = MAX_SCHEDULE_TIMEOUT;
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
2091
  	if (!ldata->icanon) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2092
2093
  		minimum = MIN_CHAR(tty);
  		if (minimum) {
a6e54319a   Peter Hurley   n_tty: Untangle r...
2094
  			time = (HZ / 10) * TIME_CHAR(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2095
  		} else {
a6e54319a   Peter Hurley   n_tty: Untangle r...
2096
  			timeout = (HZ / 10) * TIME_CHAR(tty);
33d713633   Peter Hurley   n_tty: Always wak...
2097
  			minimum = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2098
2099
  		}
  	}
04f378b19   Alan Cox   tty: BKL pushdown
2100
  	packet = tty->packet;
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
2101
  	tail = ldata->read_tail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102
2103
  
  	add_wait_queue(&tty->read_wait, &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2104
2105
  	while (nr) {
  		/* First test for status change. */
04f378b19   Alan Cox   tty: BKL pushdown
2106
  		if (packet && tty->link->ctrl_status) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2107
2108
2109
  			unsigned char cs;
  			if (b != buf)
  				break;
6054c16e8   Peter Hurley   tty: Use spin_loc...
2110
  			spin_lock_irq(&tty->link->ctrl_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
2112
  			cs = tty->link->ctrl_status;
  			tty->link->ctrl_status = 0;
6054c16e8   Peter Hurley   tty: Use spin_loc...
2113
  			spin_unlock_irq(&tty->link->ctrl_lock);
eab25a5cd   Peter Hurley   tty: audit: Never...
2114
  			if (put_user(cs, b)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2115
  				retval = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2116
2117
  				break;
  			}
eab25a5cd   Peter Hurley   tty: audit: Never...
2118
  			b++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2119
2120
2121
  			nr--;
  			break;
  		}
4edf1827e   Alan Cox   n_tty: clean up o...
2122

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2123
  		if (!input_available_p(tty, 0)) {
52bce7f8d   Peter Hurley   pty, n_tty: Simpl...
2124
  			up_read(&tty->termios_rwsem);
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2125
2126
2127
2128
2129
2130
2131
2132
2133
  			tty_buffer_flush_work(tty->port);
  			down_read(&tty->termios_rwsem);
  			if (!input_available_p(tty, 0)) {
  				if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
  					retval = -EIO;
  					break;
  				}
  				if (tty_hung_up_p(file))
  					break;
28b0f8a69   Tejun Heo   tty: make n_tty_r...
2134
2135
2136
2137
2138
2139
  				/*
  				 * Abort readers for ttys which never actually
  				 * get hung up.  See __tty_hangup().
  				 */
  				if (test_bit(TTY_HUPPING, &tty->flags))
  					break;
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2140
2141
  				if (!timeout)
  					break;
c96cf923a   Dmitry Safonov   tty: Don't block ...
2142
  				if (tty_io_nonblock(tty, file)) {
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2143
2144
2145
2146
2147
2148
2149
2150
  					retval = -EAGAIN;
  					break;
  				}
  				if (signal_pending(current)) {
  					retval = -ERESTARTSYS;
  					break;
  				}
  				up_read(&tty->termios_rwsem);
9356b535f   Peter Hurley   n_tty: Access ter...
2151

0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2152
2153
  				timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
  						timeout);
9356b535f   Peter Hurley   n_tty: Access ter...
2154

0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2155
2156
2157
  				down_read(&tty->termios_rwsem);
  				continue;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2158
  		}
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
2159
  		if (ldata->icanon && !L_EXTPROC(tty)) {
32f13521c   Peter Hurley   n_tty: Line copy ...
2160
  			retval = canon_copy_from_read_buf(tty, &b, &nr);
ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
2161
  			if (retval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2162
2163
2164
  				break;
  		} else {
  			int uncopied;
95ea90db0   Peter Hurley   n_tty: Only proce...
2165
2166
2167
  
  			/* Deal with packet mode. */
  			if (packet && b == buf) {
eab25a5cd   Peter Hurley   tty: audit: Never...
2168
  				if (put_user(TIOCPKT_DATA, b)) {
95ea90db0   Peter Hurley   n_tty: Only proce...
2169
  					retval = -EFAULT;
95ea90db0   Peter Hurley   n_tty: Only proce...
2170
2171
  					break;
  				}
eab25a5cd   Peter Hurley   tty: audit: Never...
2172
  				b++;
95ea90db0   Peter Hurley   n_tty: Only proce...
2173
2174
  				nr--;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2175
2176
2177
2178
2179
2180
2181
  			uncopied = copy_from_read_buf(tty, &b, &nr);
  			uncopied += copy_from_read_buf(tty, &b, &nr);
  			if (uncopied) {
  				retval = -EFAULT;
  				break;
  			}
  		}
6367ca72f   Peter Hurley   n_tty: Factor thr...
2182
  		n_tty_check_unthrottle(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2183
2184
2185
2186
2187
2188
  
  		if (b - buf >= minimum)
  			break;
  		if (time)
  			timeout = time;
  	}
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
2189
2190
  	if (tail != ldata->read_tail)
  		n_tty_kick_worker(tty);
42458f41d   Peter Hurley   n_tty: Ensure rea...
2191
  	up_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2192
  	remove_wait_queue(&tty->read_wait, &wait);
aebf04538   Peter Hurley   n_tty: Protect mi...
2193
  	mutex_unlock(&ldata->atomic_read_lock);
40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
2194
2195
  	if (b - buf)
  		retval = b - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2196
2197
2198
2199
2200
  
  	return retval;
  }
  
  /**
11a96d182   Alan Cox   tty: rename the r...
2201
   *	n_tty_write		-	write function for tty
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2202
2203
2204
2205
2206
   *	@tty: tty device
   *	@file: file object
   *	@buf: userspace buffer pointer
   *	@nr: size of I/O
   *
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2207
   *	Write function of the terminal device.  This is serialized with
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208
   *	respect to other write callers but not to termios changes, reads
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2209
2210
2211
2212
2213
   *	and other such events.  Since the receive code will echo characters,
   *	thus calling driver write methods, the output_lock is used in
   *	the output processing functions called here as well as in the
   *	echo processing function to protect the column state and space
   *	left in the buffer.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2214
2215
   *
   *	This code must be sure never to sleep through a hangup.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2216
2217
2218
2219
   *
   *	Locking: output_lock to protect column state and space left
   *		 (note that the process_output*() functions take this
   *		  lock themselves)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2220
   */
4edf1827e   Alan Cox   n_tty: clean up o...
2221

11a96d182   Alan Cox   tty: rename the r...
2222
  static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2223
  			   const unsigned char *buf, size_t nr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2224
2225
  {
  	const unsigned char *b = buf;
97d9e28d1   Peter Zijlstra   sched, tty: Deal ...
2226
  	DEFINE_WAIT_FUNC(wait, woken_wake_function);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2227
2228
2229
2230
2231
2232
2233
2234
2235
  	int c;
  	ssize_t retval = 0;
  
  	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
  	if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
  		retval = tty_check_change(tty);
  		if (retval)
  			return retval;
  	}
9356b535f   Peter Hurley   n_tty: Access ter...
2236
  	down_read(&tty->termios_rwsem);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2237
2238
  	/* Write out any echoed characters that are still pending */
  	process_echoes(tty);
300a6204b   Alan Cox   n_tty: clean up c...
2239

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2240
2241
  	add_wait_queue(&tty->write_wait, &wait);
  	while (1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2242
2243
2244
2245
2246
2247
2248
2249
  		if (signal_pending(current)) {
  			retval = -ERESTARTSYS;
  			break;
  		}
  		if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
  			retval = -EIO;
  			break;
  		}
582f55907   Peter Hurley   tty: Remove TTY_H...
2250
  		if (O_OPOST(tty)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251
  			while (nr > 0) {
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2252
  				ssize_t num = process_output_block(tty, b, nr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
  				if (num < 0) {
  					if (num == -EAGAIN)
  						break;
  					retval = num;
  					goto break_out;
  				}
  				b += num;
  				nr -= num;
  				if (nr == 0)
  					break;
  				c = *b;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2264
  				if (process_output(c, tty) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2265
2266
2267
  					break;
  				b++; nr--;
  			}
f34d7a5b7   Alan Cox   tty: The big oper...
2268
2269
  			if (tty->ops->flush_chars)
  				tty->ops->flush_chars(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
  		} else {
4291086b1   Peter Hurley   n_tty: Fix n_tty_...
2271
  			struct n_tty_data *ldata = tty->disc_data;
d6afe27bf   Roman Zippel   [PATCH] tty outpu...
2272
  			while (nr > 0) {
4291086b1   Peter Hurley   n_tty: Fix n_tty_...
2273
  				mutex_lock(&ldata->output_lock);
f34d7a5b7   Alan Cox   tty: The big oper...
2274
  				c = tty->ops->write(tty, b, nr);
4291086b1   Peter Hurley   n_tty: Fix n_tty_...
2275
  				mutex_unlock(&ldata->output_lock);
d6afe27bf   Roman Zippel   [PATCH] tty outpu...
2276
2277
2278
2279
2280
2281
2282
2283
  				if (c < 0) {
  					retval = c;
  					goto break_out;
  				}
  				if (!c)
  					break;
  				b += c;
  				nr -= c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2284
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2285
2286
2287
  		}
  		if (!nr)
  			break;
c96cf923a   Dmitry Safonov   tty: Don't block ...
2288
  		if (tty_io_nonblock(tty, file)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2289
2290
2291
  			retval = -EAGAIN;
  			break;
  		}
9356b535f   Peter Hurley   n_tty: Access ter...
2292
  		up_read(&tty->termios_rwsem);
97d9e28d1   Peter Zijlstra   sched, tty: Deal ...
2293
  		wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
9356b535f   Peter Hurley   n_tty: Access ter...
2294
2295
  
  		down_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2296
2297
  	}
  break_out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2298
  	remove_wait_queue(&tty->write_wait, &wait);
87108bc98   Peter Hurley   tty: n_tty: fix S...
2299
  	if (nr && tty->fasync)
ff8cb0fd6   Thomas Pfaff   tty: N_TTY SIGIO ...
2300
  		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
9356b535f   Peter Hurley   n_tty: Access ter...
2301
  	up_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2302
2303
2304
2305
  	return (b - buf) ? b - buf : retval;
  }
  
  /**
11a96d182   Alan Cox   tty: rename the r...
2306
   *	n_tty_poll		-	poll method for N_TTY
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
   *	@tty: terminal device
   *	@file: file accessing it
   *	@wait: poll table
   *
   *	Called when the line discipline is asked to poll() for data or
   *	for special events. This code is not serialized with respect to
   *	other events save open/close.
   *
   *	This code must be sure never to sleep through a hangup.
   *	Called without the kernel lock held - fine
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2317
   */
4edf1827e   Alan Cox   n_tty: clean up o...
2318

afc9a42b7   Al Viro   the rest of drive...
2319
  static __poll_t n_tty_poll(struct tty_struct *tty, struct file *file,
4edf1827e   Alan Cox   n_tty: clean up o...
2320
  							poll_table *wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2321
  {
afc9a42b7   Al Viro   the rest of drive...
2322
  	__poll_t mask = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2323
2324
2325
  
  	poll_wait(file, &tty->read_wait, wait);
  	poll_wait(file, &tty->write_wait, wait);
eafbe67f8   Peter Hurley   n_tty: Refactor i...
2326
  	if (input_available_p(tty, 1))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
2327
  		mask |= EPOLLIN | EPOLLRDNORM;
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2328
2329
2330
  	else {
  		tty_buffer_flush_work(tty->port);
  		if (input_available_p(tty, 1))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
2331
  			mask |= EPOLLIN | EPOLLRDNORM;
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2332
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2333
  	if (tty->packet && tty->link->ctrl_status)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
2334
  		mask |= EPOLLPRI | EPOLLIN | EPOLLRDNORM;
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2335
  	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
2336
  		mask |= EPOLLHUP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2337
  	if (tty_hung_up_p(file))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
2338
  		mask |= EPOLLHUP;
f34d7a5b7   Alan Cox   tty: The big oper...
2339
2340
2341
  	if (tty->ops->write && !tty_is_writelocked(tty) &&
  			tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
  			tty_write_room(tty) > 0)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
2342
  		mask |= EPOLLOUT | EPOLLWRNORM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2343
2344
  	return mask;
  }
57c941212   Jiri Slaby   TTY: n_tty, propa...
2345
  static unsigned long inq_canon(struct n_tty_data *ldata)
47afa7a5a   Alan Cox   tty: some ICANON ...
2346
  {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
2347
  	size_t nr, head, tail;
47afa7a5a   Alan Cox   tty: some ICANON ...
2348

a73d3d698   Peter Hurley   n_tty: Replace ca...
2349
  	if (ldata->canon_head == ldata->read_tail)
47afa7a5a   Alan Cox   tty: some ICANON ...
2350
  		return 0;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
2351
2352
  	head = ldata->canon_head;
  	tail = ldata->read_tail;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
2353
  	nr = head - tail;
47afa7a5a   Alan Cox   tty: some ICANON ...
2354
  	/* Skip EOF-chars.. */
3d63b7e4a   Tetsuo Handa   n_tty: Fix stall ...
2355
  	while (MASK(head) != MASK(tail)) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
2356
2357
  		if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) &&
  		    read_buf(ldata, tail) == __DISABLED_CHAR)
47afa7a5a   Alan Cox   tty: some ICANON ...
2358
  			nr--;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
2359
  		tail++;
47afa7a5a   Alan Cox   tty: some ICANON ...
2360
2361
2362
2363
2364
2365
2366
  	}
  	return nr;
  }
  
  static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
  		       unsigned int cmd, unsigned long arg)
  {
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
2367
  	struct n_tty_data *ldata = tty->disc_data;
47afa7a5a   Alan Cox   tty: some ICANON ...
2368
2369
2370
2371
2372
2373
  	int retval;
  
  	switch (cmd) {
  	case TIOCOUTQ:
  		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
  	case TIOCINQ:
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
2374
  		down_write(&tty->termios_rwsem);
966031f34   Linus Torvalds   n_tty: fix EXTPRO...
2375
  		if (L_ICANON(tty) && !L_EXTPROC(tty))
57c941212   Jiri Slaby   TTY: n_tty, propa...
2376
  			retval = inq_canon(ldata);
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
2377
2378
2379
  		else
  			retval = read_cnt(ldata);
  		up_write(&tty->termios_rwsem);
47afa7a5a   Alan Cox   tty: some ICANON ...
2380
2381
2382
2383
2384
  		return put_user(retval, (unsigned int __user *) arg);
  	default:
  		return n_tty_ioctl_helper(tty, file, cmd, arg);
  	}
  }
27228732a   Peter Hurley   tty: Eliminate gl...
2385
  static struct tty_ldisc_ops n_tty_ops = {
e10cc1df1   Paul Fulghum   tty: add compat_i...
2386
2387
2388
2389
2390
  	.magic           = TTY_LDISC_MAGIC,
  	.name            = "n_tty",
  	.open            = n_tty_open,
  	.close           = n_tty_close,
  	.flush_buffer    = n_tty_flush_buffer,
11a96d182   Alan Cox   tty: rename the r...
2391
2392
  	.read            = n_tty_read,
  	.write           = n_tty_write,
e10cc1df1   Paul Fulghum   tty: add compat_i...
2393
2394
  	.ioctl           = n_tty_ioctl,
  	.set_termios     = n_tty_set_termios,
11a96d182   Alan Cox   tty: rename the r...
2395
  	.poll            = n_tty_poll,
e10cc1df1   Paul Fulghum   tty: add compat_i...
2396
  	.receive_buf     = n_tty_receive_buf,
f6c8dbe6e   Peter Hurley   n_tty: Encapsulat...
2397
  	.write_wakeup    = n_tty_write_wakeup,
24a89d1cb   Peter Hurley   tty: Make ldisc i...
2398
  	.receive_buf2	 = n_tty_receive_buf2,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2399
  };
572b9adbd   Rodolfo Giometti   ldisc n_tty: add ...
2400
2401
2402
2403
2404
  
  /**
   *	n_tty_inherit_ops	-	inherit N_TTY methods
   *	@ops: struct tty_ldisc_ops where to save N_TTY methods
   *
27228732a   Peter Hurley   tty: Eliminate gl...
2405
   *	Enables a 'subclass' line discipline to 'inherit' N_TTY methods.
572b9adbd   Rodolfo Giometti   ldisc n_tty: add ...
2406
2407
2408
2409
   */
  
  void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
  {
27228732a   Peter Hurley   tty: Eliminate gl...
2410
  	*ops = n_tty_ops;
572b9adbd   Rodolfo Giometti   ldisc n_tty: add ...
2411
2412
2413
2414
  	ops->owner = NULL;
  	ops->refcount = ops->flags = 0;
  }
  EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
27228732a   Peter Hurley   tty: Eliminate gl...
2415
2416
2417
2418
2419
  
  void __init n_tty_init(void)
  {
  	tty_register_ldisc(N_TTY, &n_tty_ops);
  }