Blame view

drivers/tty/n_tty.c 60.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * n_tty.c --- implements the N_TTY line discipline.
4edf1827e   Alan Cox   n_tty: clean up o...
3
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
   * 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...
11
   * to N_TTY if it can not switch to any other line discipline.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
   *
   * Written by Theodore Ts'o, Copyright 1994.
4edf1827e   Alan Cox   n_tty: clean up o...
14
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
   * 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...
17
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
   * This file may be redistributed under the terms of the GNU General Public
   * License.
   *
   * Reduced memory usage for older ARM systems  - Russell King.
   *
4edf1827e   Alan Cox   n_tty: clean up o...
23
   * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
   *		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...
29
   *		Also fixed a bug in BLOCKING mode where n_tty_write returns
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
   *		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...
48
49
  #include <linux/audit.h>
  #include <linux/file.h>
300a6204b   Alan Cox   n_tty: clean up c...
50
  #include <linux/uaccess.h>
572b9adbd   Rodolfo Giometti   ldisc n_tty: add ...
51
  #include <linux/module.h>
593fb1ae4   George Spelvin   pps: Move timesta...
52
  #include <linux/ratelimit.h>
86e35aea4   Peter Hurley   n_tty: Fix build ...
53
  #include <linux/vmalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
62
63
64
  
  /* number of characters left in xmit buffer before select has we have room */
  #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
84
85
  #undef N_TTY_TRACE
  #ifdef N_TTY_TRACE
  # define n_tty_trace(f, args...)	trace_printk(f, ##args)
  #else
  # define n_tty_trace(f, args...)
  #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
  };
ce74117a1   Peter Hurley   n_tty: Get read_c...
122
123
  static inline size_t read_cnt(struct n_tty_data *ldata)
  {
a2f73be8e   Peter Hurley   n_tty: Remove rea...
124
  	return ldata->read_head - ldata->read_tail;
ce74117a1   Peter Hurley   n_tty: Get read_c...
125
  }
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
126
127
128
129
130
131
132
133
134
  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...
135
136
137
138
139
140
141
142
143
  static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i)
  {
  	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)];
  }
679e7c299   Peter Hurley   n_tty: Uninline t...
144
145
  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...
146
147
  {
  	struct n_tty_data *ldata = tty->disc_data;
679e7c299   Peter Hurley   n_tty: Uninline t...
148
149
150
151
152
  	size_t size = N_TTY_BUF_SIZE - tail;
  	const void *from = read_buf_addr(ldata, tail);
  	int uncopied;
  
  	if (n > size) {
309426ae6   Peter Hurley   tty: audit: Remov...
153
  		tty_audit_add_data(tty, from, size);
679e7c299   Peter Hurley   n_tty: Uninline t...
154
155
156
157
158
159
160
  		uncopied = copy_to_user(to, from, size);
  		if (uncopied)
  			return uncopied;
  		to += size;
  		n -= size;
  		from = ldata->read_buf;
  	}
72586c606   Laura Abbott   n_tty: Fix auditi...
161

309426ae6   Peter Hurley   tty: audit: Remov...
162
  	tty_audit_add_data(tty, from, n);
72586c606   Laura Abbott   n_tty: Fix auditi...
163
164
  	return copy_to_user(to, from, n);
  }
24a89d1cb   Peter Hurley   tty: Make ldisc i...
165
  /**
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
166
   *	n_tty_kick_worker - start input worker (if required)
24a89d1cb   Peter Hurley   tty: Make ldisc i...
167
168
   *	@tty: terminal
   *
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
169
   *	Re-schedules the flip buffer work if it may have stopped
24a89d1cb   Peter Hurley   tty: Make ldisc i...
170
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
171
172
173
174
   *	Caller holds exclusive termios_rwsem
   *	   or
   *	n_tty_read()/consumer path:
   *		holds non-exclusive termios_rwsem
24a89d1cb   Peter Hurley   tty: Make ldisc i...
175
   */
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
176
  static void n_tty_kick_worker(struct tty_struct *tty)
7879a9f9f   Peter Hurley   n_tty: Buffer wor...
177
  {
24a89d1cb   Peter Hurley   tty: Make ldisc i...
178
  	struct n_tty_data *ldata = tty->disc_data;
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
179
180
  	/* Did the input worker stop? Restart it */
  	if (unlikely(ldata->no_room)) {
24a89d1cb   Peter Hurley   tty: Make ldisc i...
181
  		ldata->no_room = 0;
ecbbfd44a   Jiri Slaby   TTY: move tty buf...
182
  		WARN_RATELIMIT(tty->port->itty == NULL,
cadf74869   Sasha Levin   tty: add missing ...
183
184
  				"scheduling with invalid itty
  ");
21622939f   Peter Hurley   tty: Add diagnost...
185
186
187
188
189
190
191
  		/* 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...
192
  		tty_buffer_restart_work(tty->port);
ecbbfd44a   Jiri Slaby   TTY: move tty buf...
193
  	}
55db4c64e   Linus Torvalds   Revert "tty: make...
194
  }
9a4aec2dd   Peter Hurley   n_tty: Move chars...
195
196
197
198
199
200
  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...
201
  		n = ldata->commit_head - ldata->read_tail;
9a4aec2dd   Peter Hurley   n_tty: Move chars...
202
203
204
205
  	else
  		n = ldata->canon_head - ldata->read_tail;
  	return n;
  }
ee0bab83c   Peter Hurley   n_tty: Move n_tty...
206
207
208
209
210
211
212
213
214
215
216
  /**
   *	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 ...
217
218
  	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
  	kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
ee0bab83c   Peter Hurley   n_tty: Move n_tty...
219
  }
4a23a4df5   Peter Hurley   n_tty: Factor 're...
220
  static void n_tty_check_throttle(struct tty_struct *tty)
6367ca72f   Peter Hurley   n_tty: Factor thr...
221
  {
a342846f9   Peter Hurley   n_tty: Fix thrott...
222
  	struct n_tty_data *ldata = tty->disc_data;
6367ca72f   Peter Hurley   n_tty: Factor thr...
223
224
225
226
227
  	/*
  	 * 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...
228
229
  	if (ldata->icanon && ldata->canon_head == ldata->read_tail)
  		return;
6367ca72f   Peter Hurley   n_tty: Factor thr...
230
231
232
  	while (1) {
  		int throttled;
  		tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
5e28cca15   Peter Hurley   n_tty: Simplify t...
233
  		if (N_TTY_BUF_SIZE - read_cnt(ldata) >= TTY_THRESHOLD_THROTTLE)
6367ca72f   Peter Hurley   n_tty: Factor thr...
234
235
236
237
238
239
240
  			break;
  		throttled = tty_throttle_safe(tty);
  		if (!throttled)
  			break;
  	}
  	__tty_set_flow_change(tty, 0);
  }
4b293492a   Peter Hurley   n_tty: Un-inline ...
241
  static void n_tty_check_unthrottle(struct tty_struct *tty)
6367ca72f   Peter Hurley   n_tty: Factor thr...
242
  {
6d27a63ca   Peter Hurley   n_tty: Fix unsafe...
243
  	if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
3afb1b394   Peter Hurley   n_tty: Special ca...
244
245
  		if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
  			return;
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
246
  		n_tty_kick_worker(tty);
6d27a63ca   Peter Hurley   n_tty: Fix unsafe...
247
  		tty_wakeup(tty->link);
3afb1b394   Peter Hurley   n_tty: Special ca...
248
249
  		return;
  	}
6367ca72f   Peter Hurley   n_tty: Factor thr...
250
251
252
253
254
255
256
257
258
259
260
261
262
  	/* 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 ...
263
  		n_tty_kick_worker(tty);
6367ca72f   Peter Hurley   n_tty: Factor thr...
264
265
266
267
268
269
  		unthrottled = tty_unthrottle_safe(tty);
  		if (!unthrottled)
  			break;
  	}
  	__tty_set_flow_change(tty, 0);
  }
17b820606   Alan Cox   tty: Minor tidyup...
270
271
272
  /**
   *	put_tty_queue		-	add character to tty
   *	@c: character
57c941212   Jiri Slaby   TTY: n_tty, propa...
273
   *	@ldata: n_tty data
17b820606   Alan Cox   tty: Minor tidyup...
274
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
275
276
277
278
   *	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...
279
   */
19e2ad6a0   Peter Hurley   n_tty: Remove ove...
280
  static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  {
8bfbe2de7   Christian Riesch   n_tty: Fix read_b...
282
283
  	*read_buf_addr(ldata, ldata->read_head) = c;
  	ldata->read_head++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
286
  }
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
   *	reset_buffer_flags	-	reset buffer state
   *	@tty: terminal to reset
   *
25518c68b   Peter Hurley   n_tty: Correct un...
290
291
   *	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...
292
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
293
294
   *	Locking: caller holds exclusive termios_rwsem
   *		 (or locking is not required)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
   */
a88a69c91   Joe Peterson   n_tty: Fix loss o...
296

b66f4fa50   Peter Hurley   n_tty: Fully init...
297
  static void reset_buffer_flags(struct n_tty_data *ldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  {
a73d3d698   Peter Hurley   n_tty: Replace ca...
299
  	ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
17bd79074   Peter Hurley   n_tty: Remove ech...
300
  	ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
70aca71f9   Peter Hurley   n_tty: Fix unorde...
301
  	ldata->commit_head = 0;
1075a6e2d   Peter Hurley   n_tty: Fix appare...
302
  	ldata->echo_mark = 0;
40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
303
  	ldata->line_start = 0;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
304

a73d3d698   Peter Hurley   n_tty: Replace ca...
305
  	ldata->erasing = 0;
3fe780b37   Jiri Slaby   TTY: move ldisc d...
306
  	bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
4d0ed1827   Peter Hurley   n_tty: Fix buffer...
307
  	ldata->push = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  }
a30737ab7   Peter Hurley   n_tty: Factor pac...
309
310
311
  static void n_tty_packet_mode_flush(struct tty_struct *tty)
  {
  	unsigned long flags;
a30737ab7   Peter Hurley   n_tty: Factor pac...
312
  	if (tty->link->packet) {
54e8e5fca   Peter Hurley   pty: Don't claim ...
313
  		spin_lock_irqsave(&tty->ctrl_lock, flags);
a30737ab7   Peter Hurley   n_tty: Factor pac...
314
  		tty->ctrl_status |= TIOCPKT_FLUSHREAD;
54e8e5fca   Peter Hurley   pty: Don't claim ...
315
  		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
e81107d4c   Kosuke Tatsukawa   tty: fix stall ca...
316
  		wake_up_interruptible(&tty->link->read_wait);
a30737ab7   Peter Hurley   n_tty: Factor pac...
317
  	}
a30737ab7   Peter Hurley   n_tty: Factor pac...
318
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
  /**
   *	n_tty_flush_buffer	-	clean input queue
   *	@tty:	terminal device
   *
25518c68b   Peter Hurley   n_tty: Correct un...
323
324
325
   *	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
326
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
327
328
329
330
   *	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
331
   */
4edf1827e   Alan Cox   n_tty: clean up o...
332
333
  
  static void n_tty_flush_buffer(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  {
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
335
  	down_write(&tty->termios_rwsem);
b66f4fa50   Peter Hurley   n_tty: Fully init...
336
  	reset_buffer_flags(tty->disc_data);
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
337
  	n_tty_kick_worker(tty);
4edf1827e   Alan Cox   n_tty: clean up o...
338

a30737ab7   Peter Hurley   n_tty: Factor pac...
339
340
  	if (tty->link)
  		n_tty_packet_mode_flush(tty);
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
341
  	up_write(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  }
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
343
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
   *	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...
351

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
358
359
360
361
362
363
  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...
364

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
368
369
370
  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...
371
   *	do_output_char			-	output one character
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
   *	@c: character (or partial unicode symbol)
   *	@tty: terminal device
a88a69c91   Joe Peterson   n_tty: Fix loss o...
374
   *	@space: space available in tty driver write buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
   *
a88a69c91   Joe Peterson   n_tty: Fix loss o...
376
377
   *	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...
378
379
   *	doing OPOST processing and putting the results in the
   *	tty driver's write buffer.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
380
381
382
383
   *
   *	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
384
   *
a88a69c91   Joe Peterson   n_tty: Fix loss o...
385
386
387
388
389
   *	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
390
   */
4edf1827e   Alan Cox   n_tty: clean up o...
391

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

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

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

f34d7a5b7   Alan Cox   tty: The big oper...
452
  	tty_put_char(tty, c);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
453
454
455
456
457
458
459
460
  	return 1;
  }
  
  /**
   *	process_output			-	output post processor
   *	@c: character (or partial unicode symbol)
   *	@tty: terminal device
   *
ee5aa7b8b   Joe Peterson   n_tty: honor opos...
461
462
463
   *	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...
464
465
466
467
468
469
470
471
   *
   *	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...
472
  	struct n_tty_data *ldata = tty->disc_data;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
473
  	int	space, retval;
bddc7152f   Jiri Slaby   TTY: move ldisc d...
474
  	mutex_lock(&ldata->output_lock);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
475
476
477
  
  	space = tty_write_room(tty);
  	retval = do_output_char(c, tty, space);
bddc7152f   Jiri Slaby   TTY: move ldisc d...
478
  	mutex_unlock(&ldata->output_lock);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
479
480
481
482
  	if (retval < 0)
  		return -1;
  	else
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
  }
  
  /**
a88a69c91   Joe Peterson   n_tty: Fix loss o...
486
   *	process_output_block		-	block post processor
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
   *	@tty: terminal device
ee5aa7b8b   Joe Peterson   n_tty: honor opos...
488
489
490
491
492
   *	@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
493
494
495
496
497
498
   *
   *	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...
499
500
501
   *	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
502
   */
4edf1827e   Alan Cox   n_tty: clean up o...
503

a88a69c91   Joe Peterson   n_tty: Fix loss o...
504
505
  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
506
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
507
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  	int	space;
bbd20759d   Thorsten Wißmann   drivers/tty: Remo...
509
  	int	i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  	const unsigned char *cp;
bddc7152f   Jiri Slaby   TTY: move ldisc d...
511
  	mutex_lock(&ldata->output_lock);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
512

f34d7a5b7   Alan Cox   tty: The big oper...
513
  	space = tty_write_room(tty);
300a6204b   Alan Cox   n_tty: clean up c...
514
  	if (!space) {
bddc7152f   Jiri Slaby   TTY: move ldisc d...
515
  		mutex_unlock(&ldata->output_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
  		return 0;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
517
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
521
  	if (nr > space)
  		nr = space;
  
  	for (i = 0, cp = buf; i < nr; i++, cp++) {
a59c0d6f1   Joe Peterson   n_tty: Fix handli...
522
523
524
  		unsigned char c = *cp;
  
  		switch (c) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
  		case '
  ':
  			if (O_ONLRET(tty))
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
528
  				ldata->column = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
  			if (O_ONLCR(tty))
  				goto break_out;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
531
  			ldata->canon_column = ldata->column;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  			break;
  		case '\r':
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
534
  			if (O_ONOCR(tty) && ldata->column == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
  				goto break_out;
  			if (O_OCRNL(tty))
  				goto break_out;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
538
  			ldata->canon_column = ldata->column = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
542
  			break;
  		case '\t':
  			goto break_out;
  		case '\b':
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
543
544
  			if (ldata->column > 0)
  				ldata->column--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
  			break;
  		default:
a59c0d6f1   Joe Peterson   n_tty: Fix handli...
547
548
549
550
  			if (!iscntrl(c)) {
  				if (O_OLCUC(tty))
  					goto break_out;
  				if (!is_continuation(c, tty))
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
551
  					ldata->column++;
a59c0d6f1   Joe Peterson   n_tty: Fix handli...
552
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
555
556
  			break;
  		}
  	}
  break_out:
f34d7a5b7   Alan Cox   tty: The big oper...
557
  	i = tty->ops->write(tty, buf, i);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
558

bddc7152f   Jiri Slaby   TTY: move ldisc d...
559
  	mutex_unlock(&ldata->output_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
  	return i;
  }
a88a69c91   Joe Peterson   n_tty: Fix loss o...
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  /**
   *	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 ...
584
   *	Locking: callers must hold output_lock
a88a69c91   Joe Peterson   n_tty: Fix loss o...
585
   */
bc5b1ec58   Peter Hurley   n_tty: Only flush...
586
  static size_t __process_echoes(struct tty_struct *tty)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
587
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
588
  	struct n_tty_data *ldata = tty->disc_data;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
589
  	int	space, old_space;
addaebccf   Peter Hurley   n_tty: Use separa...
590
  	size_t tail;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
591
  	unsigned char c;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
592

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

addaebccf   Peter Hurley   n_tty: Use separa...
595
  	tail = ldata->echo_tail;
29c7c5ca3   Peter Hurley   n_tty: Eliminate ...
596
  	while (ldata->echo_commit != tail) {
addaebccf   Peter Hurley   n_tty: Use separa...
597
  		c = echo_buf(ldata, tail);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
598
599
  		if (c == ECHO_OP_START) {
  			unsigned char op;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
600
601
602
603
604
605
606
  			int no_space_left = 0;
  
  			/*
  			 * 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...
607
  			op = echo_buf(ldata, tail + 1);
300a6204b   Alan Cox   n_tty: clean up c...
608

a88a69c91   Joe Peterson   n_tty: Fix loss o...
609
610
611
612
  			switch (op) {
  				unsigned int num_chars, num_bs;
  
  			case ECHO_OP_ERASE_TAB:
addaebccf   Peter Hurley   n_tty: Use separa...
613
  				num_chars = echo_buf(ldata, tail + 2);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
614
615
616
617
618
619
620
621
622
623
624
625
  
  				/*
  				 * 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...
626
  					num_chars += ldata->canon_column;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
627
628
629
630
631
632
633
634
635
  				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...
636
637
  					if (ldata->column > 0)
  						ldata->column--;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
638
  				}
addaebccf   Peter Hurley   n_tty: Use separa...
639
  				tail += 3;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
640
641
642
  				break;
  
  			case ECHO_OP_SET_CANON_COL:
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
643
  				ldata->canon_column = ldata->column;
addaebccf   Peter Hurley   n_tty: Use separa...
644
  				tail += 2;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
645
646
647
  				break;
  
  			case ECHO_OP_MOVE_BACK_COL:
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
648
649
  				if (ldata->column > 0)
  					ldata->column--;
addaebccf   Peter Hurley   n_tty: Use separa...
650
  				tail += 2;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
651
652
653
654
655
656
657
658
659
  				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...
660
  				ldata->column++;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
661
  				space--;
addaebccf   Peter Hurley   n_tty: Use separa...
662
  				tail += 2;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
663
664
665
  				break;
  
  			default:
a88a69c91   Joe Peterson   n_tty: Fix loss o...
666
  				/*
62b263585   Joe Peterson   n_tty: move echoc...
667
668
669
670
671
672
673
  				 * 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...
674
  				 */
62b263585   Joe Peterson   n_tty: move echoc...
675
676
677
678
679
680
  				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...
681
  				ldata->column += 2;
62b263585   Joe Peterson   n_tty: move echoc...
682
  				space -= 2;
addaebccf   Peter Hurley   n_tty: Use separa...
683
  				tail += 2;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
684
685
686
687
688
  			}
  
  			if (no_space_left)
  				break;
  		} else {
582f55907   Peter Hurley   tty: Remove TTY_H...
689
  			if (O_OPOST(tty)) {
ee5aa7b8b   Joe Peterson   n_tty: honor opos...
690
691
692
693
694
695
696
697
698
699
  				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...
700
  			tail += 1;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
701
  		}
a88a69c91   Joe Peterson   n_tty: Fix loss o...
702
  	}
cbfd0340a   Peter Hurley   n_tty: Process ec...
703
704
705
706
  	/* 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 */
  	while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
c476f6584   Roel Kluin   tty: incorrect te...
707
  		if (echo_buf(ldata, tail) == ECHO_OP_START) {
6f2225363   Peter Hurley   n_tty: Fix echo o...
708
  			if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB)
cbfd0340a   Peter Hurley   n_tty: Process ec...
709
710
711
712
713
714
  				tail += 3;
  			else
  				tail += 2;
  		} else
  			tail++;
  	}
addaebccf   Peter Hurley   n_tty: Use separa...
715
  	ldata->echo_tail = tail;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
716
  	return old_space - space;
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
717
718
719
720
721
  }
  
  static void commit_echoes(struct tty_struct *tty)
  {
  	struct n_tty_data *ldata = tty->disc_data;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
722
  	size_t nr, old, echoed;
cbfd0340a   Peter Hurley   n_tty: Process ec...
723
724
725
  	size_t head;
  
  	head = ldata->echo_head;
1075a6e2d   Peter Hurley   n_tty: Fix appare...
726
  	ldata->echo_mark = head;
cbfd0340a   Peter Hurley   n_tty: Process ec...
727
728
729
730
731
732
733
734
  	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;
  	if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
  		return;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
735

019ebdf9f   Peter Hurley   n_tty: Eliminate ...
736
  	mutex_lock(&ldata->output_lock);
cbfd0340a   Peter Hurley   n_tty: Process ec...
737
  	ldata->echo_commit = head;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
738
  	echoed = __process_echoes(tty);
bddc7152f   Jiri Slaby   TTY: move ldisc d...
739
  	mutex_unlock(&ldata->output_lock);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
740

bc5b1ec58   Peter Hurley   n_tty: Only flush...
741
  	if (echoed && tty->ops->flush_chars)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
742
743
  		tty->ops->flush_chars(tty);
  }
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
744
  static void process_echoes(struct tty_struct *tty)
17bd79074   Peter Hurley   n_tty: Remove ech...
745
746
  {
  	struct n_tty_data *ldata = tty->disc_data;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
747
  	size_t echoed;
17bd79074   Peter Hurley   n_tty: Remove ech...
748

e2613be50   Peter Hurley   n_tty: Fix stale ...
749
  	if (ldata->echo_mark == ldata->echo_tail)
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
750
751
752
  		return;
  
  	mutex_lock(&ldata->output_lock);
1075a6e2d   Peter Hurley   n_tty: Fix appare...
753
  	ldata->echo_commit = ldata->echo_mark;
bc5b1ec58   Peter Hurley   n_tty: Only flush...
754
  	echoed = __process_echoes(tty);
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
755
  	mutex_unlock(&ldata->output_lock);
bc5b1ec58   Peter Hurley   n_tty: Only flush...
756
  	if (echoed && tty->ops->flush_chars)
019ebdf9f   Peter Hurley   n_tty: Eliminate ...
757
  		tty->ops->flush_chars(tty);
17bd79074   Peter Hurley   n_tty: Remove ech...
758
  }
1075a6e2d   Peter Hurley   n_tty: Fix appare...
759
  /* NB: echo_mark and echo_head should be equivalent here */
cbfd0340a   Peter Hurley   n_tty: Process ec...
760
761
762
  static void flush_echoes(struct tty_struct *tty)
  {
  	struct n_tty_data *ldata = tty->disc_data;
39434abd9   Peter Hurley   n_tty: Fix missin...
763
764
  	if ((!L_ECHO(tty) && !L_ECHONL(tty)) ||
  	    ldata->echo_commit == ldata->echo_head)
cbfd0340a   Peter Hurley   n_tty: Process ec...
765
766
767
768
769
770
771
  		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...
772
773
774
  /**
   *	add_echo_byte	-	add a byte to the echo buffer
   *	@c: unicode byte to echo
57c941212   Jiri Slaby   TTY: n_tty, propa...
775
   *	@ldata: n_tty data
a88a69c91   Joe Peterson   n_tty: Fix loss o...
776
777
   *
   *	Add a character or operation byte to the echo buffer.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
778
   */
cbfd0340a   Peter Hurley   n_tty: Process ec...
779
  static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
780
  {
addaebccf   Peter Hurley   n_tty: Use separa...
781
  	*echo_buf_addr(ldata, ldata->echo_head++) = c;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
782
783
784
785
  }
  
  /**
   *	echo_move_back_col	-	add operation to move back a column
57c941212   Jiri Slaby   TTY: n_tty, propa...
786
   *	@ldata: n_tty data
a88a69c91   Joe Peterson   n_tty: Fix loss o...
787
788
   *
   *	Add an operation to the echo buffer to move back one column.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
789
   */
57c941212   Jiri Slaby   TTY: n_tty, propa...
790
  static void echo_move_back_col(struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
791
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
792
793
  	add_echo_byte(ECHO_OP_START, ldata);
  	add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
794
795
796
797
  }
  
  /**
   *	echo_set_canon_col	-	add operation to set the canon column
57c941212   Jiri Slaby   TTY: n_tty, propa...
798
   *	@ldata: n_tty data
a88a69c91   Joe Peterson   n_tty: Fix loss o...
799
800
801
   *
   *	Add an operation to the echo buffer to set the canon column
   *	to the current column.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
802
   */
57c941212   Jiri Slaby   TTY: n_tty, propa...
803
  static void echo_set_canon_col(struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
804
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
805
806
  	add_echo_byte(ECHO_OP_START, ldata);
  	add_echo_byte(ECHO_OP_SET_CANON_COL, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
807
808
809
810
811
812
  }
  
  /**
   *	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...
813
   *	@ldata: n_tty data
a88a69c91   Joe Peterson   n_tty: Fix loss o...
814
815
816
817
818
819
820
821
   *
   *	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...
822
823
824
   */
  
  static void echo_erase_tab(unsigned int num_chars, int after_tab,
57c941212   Jiri Slaby   TTY: n_tty, propa...
825
  			   struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
826
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
827
828
  	add_echo_byte(ECHO_OP_START, ldata);
  	add_echo_byte(ECHO_OP_ERASE_TAB, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
829
830
831
832
833
834
835
  
  	/* 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...
836

57c941212   Jiri Slaby   TTY: n_tty, propa...
837
  	add_echo_byte(num_chars, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
838
839
840
841
842
843
844
845
846
847
848
  }
  
  /**
   *	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...
849
   */
57c941212   Jiri Slaby   TTY: n_tty, propa...
850
  static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)
a88a69c91   Joe Peterson   n_tty: Fix loss o...
851
  {
a88a69c91   Joe Peterson   n_tty: Fix loss o...
852
  	if (c == ECHO_OP_START) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
853
854
  		add_echo_byte(ECHO_OP_START, ldata);
  		add_echo_byte(ECHO_OP_START, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
855
  	} else {
57c941212   Jiri Slaby   TTY: n_tty, propa...
856
  		add_echo_byte(c, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
857
  	}
a88a69c91   Joe Peterson   n_tty: Fix loss o...
858
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
  
  /**
a88a69c91   Joe Peterson   n_tty: Fix loss o...
861
   *	echo_char	-	echo a character
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
863
864
   *	@c: unicode byte to echo
   *	@tty: terminal device
   *
4edf1827e   Alan Cox   n_tty: clean up o...
865
   *	Echo user input back onto the screen. This must be called only when
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
   *	L_ECHO(tty) is true. Called from the driver receive_buf path.
17b820606   Alan Cox   tty: Minor tidyup...
867
   *
62b263585   Joe Peterson   n_tty: move echoc...
868
869
   *	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
870
871
872
873
   */
  
  static void echo_char(unsigned char c, struct tty_struct *tty)
  {
bddc7152f   Jiri Slaby   TTY: move ldisc d...
874
  	struct n_tty_data *ldata = tty->disc_data;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
875
  	if (c == ECHO_OP_START) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
876
877
  		add_echo_byte(ECHO_OP_START, ldata);
  		add_echo_byte(ECHO_OP_START, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
878
  	} else {
62b263585   Joe Peterson   n_tty: move echoc...
879
  		if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
57c941212   Jiri Slaby   TTY: n_tty, propa...
880
881
  			add_echo_byte(ECHO_OP_START, ldata);
  		add_echo_byte(c, ldata);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
882
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
  }
17b820606   Alan Cox   tty: Minor tidyup...
884
  /**
a88a69c91   Joe Peterson   n_tty: Fix loss o...
885
   *	finish_erasing		-	complete erase
57c941212   Jiri Slaby   TTY: n_tty, propa...
886
   *	@ldata: n_tty data
17b820606   Alan Cox   tty: Minor tidyup...
887
   */
a88a69c91   Joe Peterson   n_tty: Fix loss o...
888

57c941212   Jiri Slaby   TTY: n_tty, propa...
889
  static inline void finish_erasing(struct n_tty_data *ldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
891
  	if (ldata->erasing) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
892
  		echo_char_raw('/', ldata);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
893
  		ldata->erasing = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
898
899
900
901
  	}
  }
  
  /**
   *	eraser		-	handle erase function
   *	@c: character input
   *	@tty: terminal device
   *
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
902
   *	Perform erase and necessary output when an erase character is
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
   *	present in the stream from the driver layer. Handles the complexities
   *	of UTF-8 multibyte symbols.
17b820606   Alan Cox   tty: Minor tidyup...
905
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
906
907
   *	n_tty_receive_buf()/producer path:
   *		caller holds non-exclusive termios_rwsem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
   */
4edf1827e   Alan Cox   n_tty: clean up o...
909

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
  static void eraser(unsigned char c, struct tty_struct *tty)
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
912
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
  	enum { ERASE, WERASE, KILL } kill_type;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
914
915
916
  	size_t head;
  	size_t cnt;
  	int seen_alnums;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917

ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
918
  	if (ldata->read_head == ldata->canon_head) {
7e94b1d9b   Joe Peterson   n_tty: Output bel...
919
  		/* process_output('\a', tty); */ /* what do you think? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
922
923
924
925
926
927
  		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...
928
  			ldata->read_head = ldata->canon_head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
  			return;
  		}
  		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
932
  			ldata->read_head = ldata->canon_head;
57c941212   Jiri Slaby   TTY: n_tty, propa...
933
  			finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
935
936
  			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...
937
938
  				echo_char_raw('
  ', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
942
943
944
  			return;
  		}
  		kill_type = KILL;
  	}
  
  	seen_alnums = 0;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
945
946
  	while (ldata->read_head != ldata->canon_head) {
  		head = ldata->read_head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
  
  		/* erase a single possibly multibyte character */
  		do {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
950
951
  			head--;
  			c = read_buf(ldata, head);
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
952
  		} while (is_continuation(c, tty) && head != ldata->canon_head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
955
956
957
958
959
960
961
962
963
964
  
  		/* 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...
965
  		cnt = ldata->read_head - head;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
966
  		ldata->read_head = head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
  		if (L_ECHO(tty)) {
  			if (L_ECHOPRT(tty)) {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
969
  				if (!ldata->erasing) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
970
  					echo_char_raw('\\', ldata);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
971
  					ldata->erasing = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
974
975
  				}
  				/* if cnt > 1, output a multi-byte character */
  				echo_char(c, tty);
  				while (--cnt > 0) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
976
977
  					head++;
  					echo_char_raw(read_buf(ldata, head), ldata);
57c941212   Jiri Slaby   TTY: n_tty, propa...
978
  					echo_move_back_col(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
980
981
982
  				}
  			} 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...
983
984
  				unsigned int num_chars = 0;
  				int after_tab = 0;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
985
  				size_t tail = ldata->read_head;
a88a69c91   Joe Peterson   n_tty: Fix loss o...
986
987
988
989
990
991
992
993
  
  				/*
  				 * 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.
  				 */
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
994
  				while (tail != ldata->canon_head) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
995
996
  					tail--;
  					c = read_buf(ldata, tail);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
997
998
999
  					if (c == '\t') {
  						after_tab = 1;
  						break;
300a6204b   Alan Cox   n_tty: clean up c...
1000
  					} else if (iscntrl(c)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
  						if (L_ECHOCTL(tty))
a88a69c91   Joe Peterson   n_tty: Fix loss o...
1002
1003
1004
1005
  							num_chars += 2;
  					} else if (!is_continuation(c, tty)) {
  						num_chars++;
  					}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  				}
57c941212   Jiri Slaby   TTY: n_tty, propa...
1007
  				echo_erase_tab(num_chars, after_tab, ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
  			} else {
  				if (iscntrl(c) && L_ECHOCTL(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1010
1011
1012
  					echo_char_raw('\b', ldata);
  					echo_char_raw(' ', ldata);
  					echo_char_raw('\b', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
  				}
  				if (!iscntrl(c) || L_ECHOCTL(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1015
1016
1017
  					echo_char_raw('\b', ldata);
  					echo_char_raw(' ', ldata);
  					echo_char_raw('\b', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
1020
1021
1022
1023
  				}
  			}
  		}
  		if (kill_type == ERASE)
  			break;
  	}
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
1024
  	if (ldata->read_head == ldata->canon_head && L_ECHO(tty))
57c941212   Jiri Slaby   TTY: n_tty, propa...
1025
  		finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
1027
1028
1029
1030
1031
  }
  
  /**
   *	isig		-	handle the ISIG optio
   *	@sig: signal
   *	@tty: terminal
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
   *
8c985d18b   Peter Hurley   n_tty: Fix unsafe...
1033
1034
   *	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...
1035
   *
d2b6f4477   Peter Hurley   n_tty: Fix signal...
1036
1037
1038
1039
   *	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...
1040
   *	Locking: ctrl_lock
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1042

3b19e0322   Peter Hurley   n_tty: signal and...
1043
  static void __isig(int sig, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
  {
8c985d18b   Peter Hurley   n_tty: Fix unsafe...
1045
1046
1047
1048
  	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
1049
  	}
3b19e0322   Peter Hurley   n_tty: signal and...
1050
  }
d2b6f4477   Peter Hurley   n_tty: Fix signal...
1051

3b19e0322   Peter Hurley   n_tty: signal and...
1052
1053
1054
1055
1056
1057
1058
1059
1060
  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...
1061
1062
  		up_read(&tty->termios_rwsem);
  		down_write(&tty->termios_rwsem);
3b19e0322   Peter Hurley   n_tty: signal and...
1063
  		__isig(sig, tty);
d2b6f4477   Peter Hurley   n_tty: Fix signal...
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
  		/* 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
1083
1084
1085
1086
1087
1088
1089
1090
1091
  }
  
  /**
   *	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...
1092
1093
   *	n_tty_receive_buf()/producer path:
   *		caller holds non-exclusive termios_rwsem
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1094
1095
   *
   *	Note: may get exclusive termios_rwsem if flushing input buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1097

4b293492a   Peter Hurley   n_tty: Un-inline ...
1098
  static void n_tty_receive_break(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1100
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
1103
  	if (I_IGNBRK(tty))
  		return;
  	if (I_BRKINT(tty)) {
8c985d18b   Peter Hurley   n_tty: Fix unsafe...
1104
  		isig(SIGINT, tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
  		return;
  	}
  	if (I_PARMRK(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1108
1109
  		put_tty_queue('\377', ldata);
  		put_tty_queue('\0', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
  	}
57c941212   Jiri Slaby   TTY: n_tty, propa...
1111
  	put_tty_queue('\0', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  }
  
  /**
   *	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...
1126

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

53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1131
1132
1133
  	ldata->num_overrun++;
  	if (time_after(jiffies, ldata->overrun_time + HZ) ||
  			time_after(ldata->overrun_time, jiffies)) {
339f36ba1   Peter Hurley   tty: Define tty_*...
1134
1135
  		tty_warn(tty, "%d input overrun(s)
  ", ldata->num_overrun);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1136
1137
  		ldata->overrun_time = jiffies;
  		ldata->num_overrun = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
1142
1143
1144
1145
1146
  	}
  }
  
  /**
   *	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...
1147
1148
1149
1150
   *	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
1151
   */
4b293492a   Peter Hurley   n_tty: Un-inline ...
1152
  static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
  {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1154
  	struct n_tty_data *ldata = tty->disc_data;
66528f906   Peter Hurley   tty: Correct INPC...
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
  	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...
1165
  		put_tty_queue(c, ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
  }
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1167
1168
1169
  static void
  n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
  {
d2b6f4477   Peter Hurley   n_tty: Fix signal...
1170
  	isig(signal, tty);
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1171
1172
1173
1174
1175
  	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 ...
1176
1177
  	} else
  		process_echoes(tty);
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1178
1179
  	return;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
1181
1182
1183
1184
1185
  /**
   *	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...
1186
   *	This is serialized with respect to itself by the rules for the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
   *	driver above.
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1188
1189
1190
1191
   *
   *	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...
1192
1193
   *
   *	Returns 1 if LNEXT was received, else returns 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
   */
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1195
  static int
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1196
  n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1198
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
1202
  	if (I_IXON(tty)) {
  		if (c == START_CHAR(tty)) {
  			start_tty(tty);
e2613be50   Peter Hurley   n_tty: Fix stale ...
1203
  			process_echoes(tty);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1204
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1205
1206
1207
  		}
  		if (c == STOP_CHAR(tty)) {
  			stop_tty(tty);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1208
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
1210
  		}
  	}
575537b32   Joe Peterson   Resume TTY on SUS...
1211

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212
  	if (L_ISIG(tty)) {
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1213
1214
  		if (c == INTR_CHAR(tty)) {
  			n_tty_receive_signal_char(tty, SIGINT, c);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1215
  			return 0;
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1216
1217
  		} else if (c == QUIT_CHAR(tty)) {
  			n_tty_receive_signal_char(tty, SIGQUIT, c);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1218
  			return 0;
b0ac50be1   Peter Hurley   n_tty: Factor sig...
1219
1220
  		} else if (c == SUSP_CHAR(tty)) {
  			n_tty_receive_signal_char(tty, SIGTSTP, c);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1221
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
1223
  		}
  	}
575537b32   Joe Peterson   Resume TTY on SUS...
1224

855df3c08   Peter Hurley   n_tty: Eliminate ...
1225
1226
1227
1228
  	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...
1229
1230
  	if (c == '\r') {
  		if (I_IGNCR(tty))
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1231
  			return 0;
575537b32   Joe Peterson   Resume TTY on SUS...
1232
1233
1234
1235
1236
1237
  		if (I_ICRNL(tty))
  			c = '
  ';
  	} else if (c == '
  ' && I_INLCR(tty))
  		c = '\r';
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1238
  	if (ldata->icanon) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
1240
1241
  		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...
1242
  			commit_echoes(tty);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1243
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
1245
  		}
  		if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1246
  			ldata->lnext = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
  			if (L_ECHO(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1248
  				finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
  				if (L_ECHOCTL(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1250
1251
  					echo_char_raw('^', ldata);
  					echo_char_raw('\b', ldata);
17bd79074   Peter Hurley   n_tty: Remove ech...
1252
  					commit_echoes(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1253
1254
  				}
  			}
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1255
  			return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256
  		}
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1257
  		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1258
  			size_t tail = ldata->canon_head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259

57c941212   Jiri Slaby   TTY: n_tty, propa...
1260
  			finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261
  			echo_char(c, tty);
57c941212   Jiri Slaby   TTY: n_tty, propa...
1262
1263
  			echo_char_raw('
  ', ldata);
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
1264
  			while (tail != ldata->read_head) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1265
1266
  				echo_char(read_buf(ldata, tail), tty);
  				tail++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
  			}
17bd79074   Peter Hurley   n_tty: Remove ech...
1268
  			commit_echoes(tty);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1269
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270
1271
1272
  		}
  		if (c == '
  ') {
acc71bbad   Joe Peterson   n_tty: Fix hanfli...
1273
  			if (L_ECHO(tty) || L_ECHONL(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1274
1275
  				echo_char_raw('
  ', ldata);
17bd79074   Peter Hurley   n_tty: Remove ech...
1276
  				commit_echoes(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277
1278
1279
1280
  			}
  			goto handle_newline;
  		}
  		if (c == EOF_CHAR(tty)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
1283
1284
1285
1286
1287
1288
1289
  			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
1290
  				/* Record the column of first canon char. */
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
1291
  				if (ldata->canon_head == ldata->read_head)
57c941212   Jiri Slaby   TTY: n_tty, propa...
1292
  					echo_set_canon_col(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
  				echo_char(c, tty);
17bd79074   Peter Hurley   n_tty: Remove ech...
1294
  				commit_echoes(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1295
1296
1297
1298
1299
  			}
  			/*
  			 * XXX does PARMRK doubling happen for
  			 * EOL_CHAR and EOL2_CHAR?
  			 */
001ba9237   Peter Hurley   n_tty: Refactor P...
1300
  			if (c == (unsigned char) '\377' && I_PARMRK(tty))
57c941212   Jiri Slaby   TTY: n_tty, propa...
1301
  				put_tty_queue(c, ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302

4edf1827e   Alan Cox   n_tty: clean up o...
1303
  handle_newline:
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1304
  			set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags);
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1305
  			put_tty_queue(c, ldata);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1306
  			smp_store_release(&ldata->canon_head, ldata->read_head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
  			kill_fasync(&tty->fasync, SIGIO, POLL_IN);
e81107d4c   Kosuke Tatsukawa   tty: fix stall ca...
1308
  			wake_up_interruptible_poll(&tty->read_wait, POLLIN);
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1309
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1310
1311
  		}
  	}
4edf1827e   Alan Cox   n_tty: clean up o...
1312

acc71bbad   Joe Peterson   n_tty: Fix hanfli...
1313
  	if (L_ECHO(tty)) {
57c941212   Jiri Slaby   TTY: n_tty, propa...
1314
  		finish_erasing(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315
1316
  		if (c == '
  ')
57c941212   Jiri Slaby   TTY: n_tty, propa...
1317
1318
  			echo_char_raw('
  ', ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
  		else {
  			/* Record the column of first canon char. */
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
1321
  			if (ldata->canon_head == ldata->read_head)
57c941212   Jiri Slaby   TTY: n_tty, propa...
1322
  				echo_set_canon_col(ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
  			echo_char(c, tty);
  		}
17bd79074   Peter Hurley   n_tty: Remove ech...
1325
  		commit_echoes(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
  	}
001ba9237   Peter Hurley   n_tty: Refactor P...
1327
1328
  	/* PARMRK doubling check */
  	if (c == (unsigned char) '\377' && I_PARMRK(tty))
57c941212   Jiri Slaby   TTY: n_tty, propa...
1329
  		put_tty_queue(c, ldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330

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

e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1335
1336
  static inline void
  n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1337
1338
  {
  	struct n_tty_data *ldata = tty->disc_data;
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1339

e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
  	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...
1351
  	}
001ba9237   Peter Hurley   n_tty: Refactor P...
1352
1353
  	/* PARMRK doubling check */
  	if (c == (unsigned char) '\377' && I_PARMRK(tty))
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1354
1355
1356
  		put_tty_queue(c, ldata);
  	put_tty_queue(c, ldata);
  }
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1357

eb3e4668b   Peter Hurley   n_tty: Un-inline ...
1358
  static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1359
1360
  {
  	n_tty_receive_char_inline(tty, c);
4b1f79c2d   Peter Hurley   n_tty: Split n_tt...
1361
  }
ad0cc7baf   Peter Hurley   n_tty: Factor tty...
1362
  static inline void
7de971b05   Peter Hurley   n_tty: Factor PAR...
1363
1364
1365
  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...
1366
1367
1368
  	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...
1369
  	}
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1370
1371
1372
1373
1374
1375
1376
1377
1378
  	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...
1379
  }
8dc4b25d2   Peter Hurley   n_tty: Un-inline ...
1380
  static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
ad0cc7baf   Peter Hurley   n_tty: Factor tty...
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
  {
  	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...
1399
1400
1401
  static void
  n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
  {
d2f8d7abd   Peter Hurley   n_tty: Factor fla...
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
  	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_*...
1414
1415
  		tty_err(tty, "unknown flag %d
  ", flag);
d2f8d7abd   Peter Hurley   n_tty: Factor fla...
1416
1417
1418
  		break;
  	}
  }
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
  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...
1434
1435
1436
1437
1438
1439
1440
1441
  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...
1442
  	n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
4a23a4df5   Peter Hurley   n_tty: Factor 're...
1443
1444
1445
1446
1447
1448
  	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...
1449
  	n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
4a23a4df5   Peter Hurley   n_tty: Factor 're...
1450
1451
1452
  	memcpy(read_buf_addr(ldata, head), cp, n);
  	ldata->read_head += n;
  }
554117bdc   Peter Hurley   n_tty: Factor raw...
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
  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...
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
  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...
1480
1481
  	}
  }
7d88d637a   Peter Hurley   n_tty: Factor sta...
1482
1483
  static void
  n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp,
6baad0086   Peter Hurley   n_tty: Factor IST...
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
  			  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...
1503
1504
1505
1506
1507
1508
1509
1510
  			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...
1511
1512
1513
1514
1515
1516
1517
1518
  		} 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...
1519
  {
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1520
  	struct n_tty_data *ldata = tty->disc_data;
7d88d637a   Peter Hurley   n_tty: Factor sta...
1521
1522
1523
1524
1525
  	char flag = TTY_NORMAL;
  
  	while (count--) {
  		if (fp)
  			flag = *fp++;
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
  		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...
1538
1539
1540
  			n_tty_receive_char_flagged(tty, *cp++, flag);
  	}
  }
24a89d1cb   Peter Hurley   tty: Make ldisc i...
1541
1542
  static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
  			  char *fp, int count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1544
  	struct n_tty_data *ldata = tty->disc_data;
a1dd30e9b   Peter Hurley   n_tty: Special ca...
1545
  	bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1546

4a23a4df5   Peter Hurley   n_tty: Factor 're...
1547
1548
  	if (ldata->real_raw)
  		n_tty_receive_buf_real_raw(tty, cp, fp, count);
a1dd30e9b   Peter Hurley   n_tty: Special ca...
1549
  	else if (ldata->raw || (L_EXTPROC(tty) && !preops))
554117bdc   Peter Hurley   n_tty: Factor raw...
1550
  		n_tty_receive_buf_raw(tty, cp, fp, count);
ad0cc7baf   Peter Hurley   n_tty: Factor tty...
1551
1552
  	else if (tty->closing && !L_EXTPROC(tty))
  		n_tty_receive_buf_closing(tty, cp, fp, count);
4a23a4df5   Peter Hurley   n_tty: Factor 're...
1553
  	else {
e60d27c4d   Peter Hurley   n_tty: Factor LNE...
1554
1555
1556
1557
1558
1559
1560
1561
  		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...
1562
  		if (!preops && !I_PARMRK(tty))
6baad0086   Peter Hurley   n_tty: Factor IST...
1563
1564
1565
  			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...
1566
1567
  
  		flush_echoes(tty);
f34d7a5b7   Alan Cox   tty: The big oper...
1568
1569
  		if (tty->ops->flush_chars)
  			tty->ops->flush_chars(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
  	}
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1571
1572
1573
1574
1575
  	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...
1576
  	if (read_cnt(ldata)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
  		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
e81107d4c   Kosuke Tatsukawa   tty: fix stall ca...
1578
  		wake_up_interruptible_poll(&tty->read_wait, POLLIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1580
  }
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
  /**
   *	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...
1614
1615
1616
  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...
1617
1618
  {
  	struct n_tty_data *ldata = tty->disc_data;
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1619
  	int room, n, rcvd = 0, overflow;
24a89d1cb   Peter Hurley   tty: Make ldisc i...
1620

9356b535f   Peter Hurley   n_tty: Access ter...
1621
  	down_read(&tty->termios_rwsem);
19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1622
  	while (1) {
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1623
  		/*
06c49f9fa   Peter Hurley   n_tty: Fix PARMRK...
1624
1625
  		 * 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...
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
  		 *
  		 * 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...
1637

fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1638
  		room = N_TTY_BUF_SIZE - (ldata->read_head - tail);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1639
  		if (I_PARMRK(tty))
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
  			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...
1650

19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1651
  		n = min(count, room);
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1652
  		if (!n)
19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1653
  			break;
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1654
1655
1656
1657
  
  		/* 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...
1658
1659
1660
1661
1662
  		cp += n;
  		if (fp)
  			fp += n;
  		count -= n;
  		rcvd += n;
4a23a4df5   Peter Hurley   n_tty: Factor 're...
1663
  	}
24a89d1cb   Peter Hurley   tty: Make ldisc i...
1664

19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1665
  	tty->receive_room = room;
fb5ef9e7d   Peter Hurley   n_tty: Fix read b...
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
  
  	/* 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...
1676
  	up_read(&tty->termios_rwsem);
19e2ad6a0   Peter Hurley   n_tty: Remove ove...
1677
  	return rcvd;
24a89d1cb   Peter Hurley   tty: Make ldisc i...
1678
  }
5c32d1237   Peter Hurley   n_tty: Merge .rec...
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
  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
1690
1691
1692
1693
1694
1695
1696
  /**
   *	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...
1697
   *	and is protected from re-entry by the tty layer. The user is
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1698
1699
   *	guaranteed that this function will not be re-entered or in progress
   *	when the ldisc is closed.
17b820606   Alan Cox   tty: Minor tidyup...
1700
   *
6a1c0680c   Peter Hurley   tty: Convert term...
1701
   *	Locking: Caller holds tty->termios_rwsem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1702
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1703
1704
  
  static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1705
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1706
  	struct n_tty_data *ldata = tty->disc_data;
47afa7a5a   Alan Cox   tty: some ICANON ...
1707

c786f74e0   Peter Hurley   n_tty: Remove unn...
1708
  	if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) {
3fe780b37   Jiri Slaby   TTY: move ldisc d...
1709
  		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
4d0ed1827   Peter Hurley   n_tty: Fix buffer...
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
  		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...
1720
  		ldata->commit_head = ldata->read_head;
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1721
  		ldata->erasing = 0;
6f9b028a8   Peter Hurley   n_tty: Reset lnex...
1722
  		ldata->lnext = 0;
47afa7a5a   Alan Cox   tty: some ICANON ...
1723
  	}
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1724
  	ldata->icanon = (L_ICANON(tty) != 0);
582f55907   Peter Hurley   tty: Remove TTY_H...
1725

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1726
1727
1728
1729
  	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...
1730
  		bitmap_zero(ldata->char_map, 256);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1731
1732
  
  		if (I_IGNCR(tty) || I_ICRNL(tty))
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1733
  			set_bit('\r', ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1734
  		if (I_INLCR(tty))
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1735
1736
  			set_bit('
  ', ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1737
1738
  
  		if (L_ICANON(tty)) {
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1739
1740
1741
1742
1743
1744
  			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
1745
  			if (L_IEXTEN(tty)) {
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1746
1747
1748
  				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
1749
1750
  				if (L_ECHO(tty))
  					set_bit(REPRINT_CHAR(tty),
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1751
  						ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1752
1753
1754
  			}
  		}
  		if (I_IXON(tty)) {
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1755
1756
  			set_bit(START_CHAR(tty), ldata->char_map);
  			set_bit(STOP_CHAR(tty), ldata->char_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1757
1758
  		}
  		if (L_ISIG(tty)) {
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1759
1760
1761
  			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
1762
  		}
1bb9d5628   Peter Hurley   n_tty: Rename pro...
1763
  		clear_bit(__DISABLED_CHAR, ldata->char_map);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1764
1765
  		ldata->raw = 0;
  		ldata->real_raw = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1766
  	} else {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1767
  		ldata->raw = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1768
1769
1770
  		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...
1771
  			ldata->real_raw = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772
  		else
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1773
  			ldata->real_raw = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1774
  	}
dab73b4eb   Wang YanQing   TTY: Fix tty miss...
1775
1776
1777
1778
  	/*
  	 * 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 ...
1779
  	if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
dab73b4eb   Wang YanQing   TTY: Fix tty miss...
1780
  		start_tty(tty);
e2613be50   Peter Hurley   n_tty: Fix stale ...
1781
1782
  		process_echoes(tty);
  	}
dab73b4eb   Wang YanQing   TTY: Fix tty miss...
1783

f34d7a5b7   Alan Cox   tty: The big oper...
1784
  	/* The termios change make the tty ready for I/O */
e81107d4c   Kosuke Tatsukawa   tty: fix stall ca...
1785
1786
  	wake_up_interruptible(&tty->write_wait);
  	wake_up_interruptible(&tty->read_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1787
1788
1789
1790
1791
1792
  }
  
  /**
   *	n_tty_close		-	close the ldisc for this tty
   *	@tty: device
   *
4edf1827e   Alan Cox   n_tty: clean up o...
1793
1794
   *	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
1795
1796
1797
   *	discipline change. The function will not be called while other
   *	ldisc methods are in progress.
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1798

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1799
1800
  static void n_tty_close(struct tty_struct *tty)
  {
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1801
  	struct n_tty_data *ldata = tty->disc_data;
79901317c   Peter Hurley   n_tty: Don't flus...
1802
1803
  	if (tty->link)
  		n_tty_packet_mode_flush(tty);
20bafb3d2   Peter Hurley   n_tty: Move buffe...
1804
  	vfree(ldata);
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1805
  	tty->disc_data = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1806
1807
1808
1809
1810
1811
  }
  
  /**
   *	n_tty_open		-	open an ldisc
   *	@tty: terminal to open
   *
4edf1827e   Alan Cox   n_tty: clean up o...
1812
   *	Called when this line discipline is being attached to the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1813
1814
1815
1816
1817
1818
1819
   *	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...
1820
  	struct n_tty_data *ldata;
20bafb3d2   Peter Hurley   n_tty: Move buffe...
1821
1822
  	/* Currently a malloc failure here can panic */
  	ldata = vmalloc(sizeof(*ldata));
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1823
1824
  	if (!ldata)
  		goto err;
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1825
  	ldata->overrun_time = jiffies;
bddc7152f   Jiri Slaby   TTY: move ldisc d...
1826
1827
  	mutex_init(&ldata->atomic_read_lock);
  	mutex_init(&ldata->output_lock);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1828

70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1829
  	tty->disc_data = ldata;
b66f4fa50   Peter Hurley   n_tty: Fully init...
1830
  	reset_buffer_flags(tty->disc_data);
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1831
  	ldata->column = 0;
20bafb3d2   Peter Hurley   n_tty: Move buffe...
1832
  	ldata->canon_column = 0;
20bafb3d2   Peter Hurley   n_tty: Move buffe...
1833
1834
1835
  	ldata->num_overrun = 0;
  	ldata->no_room = 0;
  	ldata->lnext = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1836
  	tty->closing = 0;
b66f4fa50   Peter Hurley   n_tty: Fully init...
1837
1838
1839
1840
  	/* indicate buffer work may resume */
  	clear_bit(TTY_LDISC_HALTED, &tty->flags);
  	n_tty_set_termios(tty, NULL);
  	tty_unthrottle(tty);
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1841

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1842
  	return 0;
70ece7a73   Jiri Slaby   TTY: n_tty, add l...
1843
  err:
b91939f52   Jiri Slaby   TTY: n_tty, simpl...
1844
  	return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1845
  }
eafbe67f8   Peter Hurley   n_tty: Refactor i...
1846
  static inline int input_available_p(struct tty_struct *tty, int poll)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1847
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1848
  	struct n_tty_data *ldata = tty->disc_data;
a5934804a   Peter Hurley   n_tty: Fix poll()...
1849
  	int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1850

25e8d0ed7   Peter Hurley   n_tty: Simplify i...
1851
1852
1853
  	if (ldata->icanon && !L_EXTPROC(tty))
  		return ldata->canon_head != ldata->read_tail;
  	else
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1854
  		return ldata->commit_head - ldata->read_tail >= amt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1855
1856
1857
  }
  
  /**
bbd20759d   Thorsten Wißmann   drivers/tty: Remo...
1858
   *	copy_from_read_buf	-	copy read data directly
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859
1860
1861
1862
   *	@tty: terminal device
   *	@b: user data
   *	@nr: size of data
   *
11a96d182   Alan Cox   tty: rename the r...
1863
   *	Helper function to speed up n_tty_read.  It is only called when
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1864
1865
1866
1867
1868
1869
   *	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...
1870
   *	Called under the ldata->atomic_read_lock sem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1871
   *
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1872
1873
1874
   *	n_tty_read()/consumer path:
   *		caller holds non-exclusive termios_rwsem
   *		read_tail published
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
   */
4edf1827e   Alan Cox   n_tty: clean up o...
1876

33f0f88f1   Alan Cox   [PATCH] TTY layer...
1877
  static int copy_from_read_buf(struct tty_struct *tty,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
1879
1880
1881
  				      unsigned char __user **b,
  				      size_t *nr)
  
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
1882
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1883
1884
  	int retval;
  	size_t n;
3fa10cc83   Jiri Slaby   TTY: n_tty, do no...
1885
  	bool is_eof;
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1886
  	size_t head = smp_load_acquire(&ldata->commit_head);
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1887
  	size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1888
1889
  
  	retval = 0;
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1890
  	n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1891
  	n = min(*nr, n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1892
  	if (n) {
e661cf702   Peter Hurley   n_tty: Clarify co...
1893
1894
  		const unsigned char *from = read_buf_addr(ldata, tail);
  		retval = copy_to_user(*b, from, n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1895
  		n -= retval;
e661cf702   Peter Hurley   n_tty: Clarify co...
1896
  		is_eof = n == 1 && *from == EOF_CHAR(tty);
309426ae6   Peter Hurley   tty: audit: Remov...
1897
  		tty_audit_add_data(tty, from, n);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1898
  		smp_store_release(&ldata->read_tail, ldata->read_tail + n);
26df6d134   hyc@symas.com   tty: Add EXTPROC ...
1899
  		/* Turn single EOF into zero-length read */
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1900
1901
  		if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
  		    (head == ldata->read_tail))
3fa10cc83   Jiri Slaby   TTY: n_tty, do no...
1902
  			n = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1903
1904
1905
1906
1907
  		*b += n;
  		*nr -= n;
  	}
  	return retval;
  }
88bb0de38   Peter Hurley   n_tty: Factor can...
1908
  /**
32f13521c   Peter Hurley   n_tty: Line copy ...
1909
   *	canon_copy_from_read_buf	-	copy read data in canonical mode
88bb0de38   Peter Hurley   n_tty: Factor can...
1910
1911
1912
1913
1914
   *	@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 ...
1915
1916
   *	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...
1917
   *
4d0ed1827   Peter Hurley   n_tty: Fix buffer...
1918
1919
1920
1921
1922
1923
   *	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...
1924
   *	Called under the atomic_read_lock mutex
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1925
1926
1927
1928
   *
   *	n_tty_read()/consumer path:
   *		caller holds non-exclusive termios_rwsem
   *		read_tail published
88bb0de38   Peter Hurley   n_tty: Factor can...
1929
   */
32f13521c   Peter Hurley   n_tty: Line copy ...
1930
1931
1932
  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...
1933
1934
  {
  	struct n_tty_data *ldata = tty->disc_data;
32f13521c   Peter Hurley   n_tty: Line copy ...
1935
  	size_t n, size, more, c;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1936
1937
1938
  	size_t eol;
  	size_t tail;
  	int ret, found = 0;
88bb0de38   Peter Hurley   n_tty: Factor can...
1939
1940
  
  	/* N.B. avoid overrun if nr == 0 */
ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
1941
  	if (!*nr)
32f13521c   Peter Hurley   n_tty: Line copy ...
1942
  		return 0;
88bb0de38   Peter Hurley   n_tty: Factor can...
1943

ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
1944
  	n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1945
  	tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
32f13521c   Peter Hurley   n_tty: Line copy ...
1946
  	size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
1947
1948
  	n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu
  ",
32f13521c   Peter Hurley   n_tty: Line copy ...
1949
1950
1951
1952
1953
1954
1955
  		    __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...
1956
1957
1958
  		found = eol != more;
  	} else
  		found = eol != size;
32f13521c   Peter Hurley   n_tty: Line copy ...
1959

c77569d2f   Peter Hurley   n_tty: Fix 4096-b...
1960
  	n = eol - tail;
da555db6b   Mark Tomlinson   n_tty: Fix calcul...
1961
1962
  	if (n > N_TTY_BUF_SIZE)
  		n += N_TTY_BUF_SIZE;
ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
1963
  	c = n + found;
32f13521c   Peter Hurley   n_tty: Line copy ...
1964

ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
1965
1966
1967
  	if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) {
  		c = min(*nr, c);
  		n = c;
40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
1968
  	}
32f13521c   Peter Hurley   n_tty: Line copy ...
1969

679e7c299   Peter Hurley   n_tty: Uninline t...
1970
1971
1972
  	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 ...
1973

679e7c299   Peter Hurley   n_tty: Uninline t...
1974
  	ret = tty_copy_to_user(tty, *b, tail, n);
32f13521c   Peter Hurley   n_tty: Line copy ...
1975
1976
1977
1978
  	if (ret)
  		return -EFAULT;
  	*b += n;
  	*nr -= n;
a73d3d698   Peter Hurley   n_tty: Replace ca...
1979
  	if (found)
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
1980
  		clear_bit(eol, ldata->read_flags);
70aca71f9   Peter Hurley   n_tty: Fix unorde...
1981
  	smp_store_release(&ldata->read_tail, ldata->read_tail + c);
88bb0de38   Peter Hurley   n_tty: Factor can...
1982

40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
1983
  	if (found) {
4d0ed1827   Peter Hurley   n_tty: Fix buffer...
1984
1985
1986
1987
  		if (!ldata->push)
  			ldata->line_start = ldata->read_tail;
  		else
  			ldata->push = 0;
b50819f43   Peter Hurley   tty: audit: Ignor...
1988
  		tty_audit_push();
40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
1989
  	}
ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
1990
  	return 0;
88bb0de38   Peter Hurley   n_tty: Factor can...
1991
  }
cc4191dc1   Al Viro   drivers/char/n_tt...
1992
  extern ssize_t redirected_tty_write(struct file *, const char __user *,
4edf1827e   Alan Cox   n_tty: clean up o...
1993
  							size_t, loff_t *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1994
1995
1996
1997
1998
1999
2000
  
  /**
   *	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...
2001
   *	and if appropriate send any needed signals and return a negative
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2002
   *	error code if action should be taken.
04f378b19   Alan Cox   tty: BKL pushdown
2003
   *
01a5e440c   Peter Hurley   n_tty: Lock acces...
2004
2005
2006
   *	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
2007
   */
4edf1827e   Alan Cox   n_tty: clean up o...
2008

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2009
2010
2011
2012
2013
2014
2015
  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...
2016
  	if (file->f_op->write == redirected_tty_write)
01a5e440c   Peter Hurley   n_tty: Lock acces...
2017
  		return 0;
2812d9e9f   Peter Hurley   tty: Combine SIGT...
2018
  	return __tty_check_change(tty, SIGTTIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2019
  }
4edf1827e   Alan Cox   n_tty: clean up o...
2020

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2021
2022
  
  /**
11a96d182   Alan Cox   tty: rename the r...
2023
   *	n_tty_read		-	read function for tty
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
   *	@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...
2035
2036
2037
2038
   *
   *	n_tty_read()/consumer path:
   *		claims non-exclusive termios_rwsem
   *		publishes read_tail
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
   */
4edf1827e   Alan Cox   n_tty: clean up o...
2040

11a96d182   Alan Cox   tty: rename the r...
2041
  static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2042
2043
  			 unsigned char __user *buf, size_t nr)
  {
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
2044
  	struct n_tty_data *ldata = tty->disc_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2045
  	unsigned char __user *b = buf;
97d9e28d1   Peter Zijlstra   sched, tty: Deal ...
2046
  	DEFINE_WAIT_FUNC(wait, woken_wake_function);
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2047
  	int c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2048
2049
  	int minimum, time;
  	ssize_t retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2050
  	long timeout;
04f378b19   Alan Cox   tty: BKL pushdown
2051
  	int packet;
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
2052
  	size_t tail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2053

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
  	c = job_control(tty, file);
4edf1827e   Alan Cox   n_tty: clean up o...
2055
  	if (c < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2056
  		return c;
4edf1827e   Alan Cox   n_tty: clean up o...
2057

aefceaf45   Peter Hurley   n_tty: Fix termio...
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
  	/*
  	 *	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...
2068
  	down_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
2070
  	minimum = time = 0;
  	timeout = MAX_SCHEDULE_TIMEOUT;
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
2071
  	if (!ldata->icanon) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2072
2073
  		minimum = MIN_CHAR(tty);
  		if (minimum) {
a6e54319a   Peter Hurley   n_tty: Untangle r...
2074
  			time = (HZ / 10) * TIME_CHAR(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2075
  		} else {
a6e54319a   Peter Hurley   n_tty: Untangle r...
2076
  			timeout = (HZ / 10) * TIME_CHAR(tty);
33d713633   Peter Hurley   n_tty: Always wak...
2077
  			minimum = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2078
2079
  		}
  	}
04f378b19   Alan Cox   tty: BKL pushdown
2080
  	packet = tty->packet;
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
2081
  	tail = ldata->read_tail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082
2083
  
  	add_wait_queue(&tty->read_wait, &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2084
2085
  	while (nr) {
  		/* First test for status change. */
04f378b19   Alan Cox   tty: BKL pushdown
2086
  		if (packet && tty->link->ctrl_status) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2087
2088
2089
  			unsigned char cs;
  			if (b != buf)
  				break;
6054c16e8   Peter Hurley   tty: Use spin_loc...
2090
  			spin_lock_irq(&tty->link->ctrl_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
  			cs = tty->link->ctrl_status;
  			tty->link->ctrl_status = 0;
6054c16e8   Peter Hurley   tty: Use spin_loc...
2093
  			spin_unlock_irq(&tty->link->ctrl_lock);
eab25a5cd   Peter Hurley   tty: audit: Never...
2094
  			if (put_user(cs, b)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2095
  				retval = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2096
2097
  				break;
  			}
eab25a5cd   Peter Hurley   tty: audit: Never...
2098
  			b++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2099
2100
2101
  			nr--;
  			break;
  		}
4edf1827e   Alan Cox   n_tty: clean up o...
2102

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2103
  		if (!input_available_p(tty, 0)) {
52bce7f8d   Peter Hurley   pty, n_tty: Simpl...
2104
  			up_read(&tty->termios_rwsem);
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
  			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;
  				if (!timeout)
  					break;
  				if (file->f_flags & O_NONBLOCK) {
  					retval = -EAGAIN;
  					break;
  				}
  				if (signal_pending(current)) {
  					retval = -ERESTARTSYS;
  					break;
  				}
  				up_read(&tty->termios_rwsem);
9356b535f   Peter Hurley   n_tty: Access ter...
2125

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

0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2129
2130
2131
  				down_read(&tty->termios_rwsem);
  				continue;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2132
  		}
53c5ee2cf   Jiri Slaby   TTY: move ldisc d...
2133
  		if (ldata->icanon && !L_EXTPROC(tty)) {
32f13521c   Peter Hurley   n_tty: Line copy ...
2134
  			retval = canon_copy_from_read_buf(tty, &b, &nr);
ac8f3bf88   Peter Hurley   n_tty: Fix poll()...
2135
  			if (retval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2136
2137
2138
  				break;
  		} else {
  			int uncopied;
95ea90db0   Peter Hurley   n_tty: Only proce...
2139
2140
2141
  
  			/* Deal with packet mode. */
  			if (packet && b == buf) {
eab25a5cd   Peter Hurley   tty: audit: Never...
2142
  				if (put_user(TIOCPKT_DATA, b)) {
95ea90db0   Peter Hurley   n_tty: Only proce...
2143
  					retval = -EFAULT;
95ea90db0   Peter Hurley   n_tty: Only proce...
2144
2145
  					break;
  				}
eab25a5cd   Peter Hurley   tty: audit: Never...
2146
  				b++;
95ea90db0   Peter Hurley   n_tty: Only proce...
2147
2148
  				nr--;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2149
2150
2151
2152
2153
2154
2155
  			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...
2156
  		n_tty_check_unthrottle(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2157
2158
2159
2160
2161
2162
  
  		if (b - buf >= minimum)
  			break;
  		if (time)
  			timeout = time;
  	}
2c5dc4641   Peter Hurley   n_tty: Eliminate ...
2163
2164
  	if (tail != ldata->read_tail)
  		n_tty_kick_worker(tty);
42458f41d   Peter Hurley   n_tty: Ensure rea...
2165
  	up_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
  	remove_wait_queue(&tty->read_wait, &wait);
aebf04538   Peter Hurley   n_tty: Protect mi...
2167
  	mutex_unlock(&ldata->atomic_read_lock);
40d5e0905   Peter Hurley   n_tty: Fix EOF pu...
2168
2169
  	if (b - buf)
  		retval = b - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2170
2171
2172
2173
2174
  
  	return retval;
  }
  
  /**
11a96d182   Alan Cox   tty: rename the r...
2175
   *	n_tty_write		-	write function for tty
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176
2177
2178
2179
2180
   *	@tty: tty device
   *	@file: file object
   *	@buf: userspace buffer pointer
   *	@nr: size of I/O
   *
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2181
   *	Write function of the terminal device.  This is serialized with
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182
   *	respect to other write callers but not to termios changes, reads
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2183
2184
2185
2186
2187
   *	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
2188
2189
   *
   *	This code must be sure never to sleep through a hangup.
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2190
2191
2192
2193
   *
   *	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
2194
   */
4edf1827e   Alan Cox   n_tty: clean up o...
2195

11a96d182   Alan Cox   tty: rename the r...
2196
  static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2197
  			   const unsigned char *buf, size_t nr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2198
2199
  {
  	const unsigned char *b = buf;
97d9e28d1   Peter Zijlstra   sched, tty: Deal ...
2200
  	DEFINE_WAIT_FUNC(wait, woken_wake_function);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2201
2202
2203
2204
2205
2206
2207
2208
2209
  	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...
2210
  	down_read(&tty->termios_rwsem);
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2211
2212
  	/* Write out any echoed characters that are still pending */
  	process_echoes(tty);
300a6204b   Alan Cox   n_tty: clean up c...
2213

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2214
2215
  	add_wait_queue(&tty->write_wait, &wait);
  	while (1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2216
2217
2218
2219
2220
2221
2222
2223
  		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...
2224
  		if (O_OPOST(tty)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
  			while (nr > 0) {
a88a69c91   Joe Peterson   n_tty: Fix loss o...
2226
  				ssize_t num = process_output_block(tty, b, nr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
  				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...
2238
  				if (process_output(c, tty) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2239
2240
2241
  					break;
  				b++; nr--;
  			}
f34d7a5b7   Alan Cox   tty: The big oper...
2242
2243
  			if (tty->ops->flush_chars)
  				tty->ops->flush_chars(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2244
  		} else {
4291086b1   Peter Hurley   n_tty: Fix n_tty_...
2245
  			struct n_tty_data *ldata = tty->disc_data;
d6afe27bf   Roman Zippel   [PATCH] tty outpu...
2246
  			while (nr > 0) {
4291086b1   Peter Hurley   n_tty: Fix n_tty_...
2247
  				mutex_lock(&ldata->output_lock);
f34d7a5b7   Alan Cox   tty: The big oper...
2248
  				c = tty->ops->write(tty, b, nr);
4291086b1   Peter Hurley   n_tty: Fix n_tty_...
2249
  				mutex_unlock(&ldata->output_lock);
d6afe27bf   Roman Zippel   [PATCH] tty outpu...
2250
2251
2252
2253
2254
2255
2256
2257
  				if (c < 0) {
  					retval = c;
  					goto break_out;
  				}
  				if (!c)
  					break;
  				b += c;
  				nr -= c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2258
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2259
2260
2261
2262
2263
2264
2265
  		}
  		if (!nr)
  			break;
  		if (file->f_flags & O_NONBLOCK) {
  			retval = -EAGAIN;
  			break;
  		}
9356b535f   Peter Hurley   n_tty: Access ter...
2266
  		up_read(&tty->termios_rwsem);
97d9e28d1   Peter Zijlstra   sched, tty: Deal ...
2267
  		wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
9356b535f   Peter Hurley   n_tty: Access ter...
2268
2269
  
  		down_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
2271
  	}
  break_out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
  	remove_wait_queue(&tty->write_wait, &wait);
87108bc98   Peter Hurley   tty: n_tty: fix S...
2273
  	if (nr && tty->fasync)
ff8cb0fd6   Thomas Pfaff   tty: N_TTY SIGIO ...
2274
  		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
9356b535f   Peter Hurley   n_tty: Access ter...
2275
  	up_read(&tty->termios_rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2276
2277
2278
2279
  	return (b - buf) ? b - buf : retval;
  }
  
  /**
11a96d182   Alan Cox   tty: rename the r...
2280
   *	n_tty_poll		-	poll method for N_TTY
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
   *	@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
2291
   */
4edf1827e   Alan Cox   n_tty: clean up o...
2292

11a96d182   Alan Cox   tty: rename the r...
2293
  static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
4edf1827e   Alan Cox   n_tty: clean up o...
2294
  							poll_table *wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2295
2296
2297
2298
2299
  {
  	unsigned int mask = 0;
  
  	poll_wait(file, &tty->read_wait, wait);
  	poll_wait(file, &tty->write_wait, wait);
eafbe67f8   Peter Hurley   n_tty: Refactor i...
2300
  	if (input_available_p(tty, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301
  		mask |= POLLIN | POLLRDNORM;
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2302
2303
2304
2305
2306
  	else {
  		tty_buffer_flush_work(tty->port);
  		if (input_available_p(tty, 1))
  			mask |= POLLIN | POLLRDNORM;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
2308
  	if (tty->packet && tty->link->ctrl_status)
  		mask |= POLLPRI | POLLIN | POLLRDNORM;
0f40fbbcc   Brian Bloniarz   Fix OpenSSH pty r...
2309
2310
  	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
  		mask |= POLLHUP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311
2312
  	if (tty_hung_up_p(file))
  		mask |= POLLHUP;
f34d7a5b7   Alan Cox   tty: The big oper...
2313
2314
2315
  	if (tty->ops->write && !tty_is_writelocked(tty) &&
  			tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
  			tty_write_room(tty) > 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2316
2317
2318
  		mask |= POLLOUT | POLLWRNORM;
  	return mask;
  }
57c941212   Jiri Slaby   TTY: n_tty, propa...
2319
  static unsigned long inq_canon(struct n_tty_data *ldata)
47afa7a5a   Alan Cox   tty: some ICANON ...
2320
  {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
2321
  	size_t nr, head, tail;
47afa7a5a   Alan Cox   tty: some ICANON ...
2322

a73d3d698   Peter Hurley   n_tty: Replace ca...
2323
  	if (ldata->canon_head == ldata->read_tail)
47afa7a5a   Alan Cox   tty: some ICANON ...
2324
  		return 0;
ba2e68ac6   Jiri Slaby   TTY: move ldisc d...
2325
2326
  	head = ldata->canon_head;
  	tail = ldata->read_tail;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
2327
  	nr = head - tail;
47afa7a5a   Alan Cox   tty: some ICANON ...
2328
2329
  	/* Skip EOF-chars.. */
  	while (head != tail) {
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
2330
2331
  		if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) &&
  		    read_buf(ldata, tail) == __DISABLED_CHAR)
47afa7a5a   Alan Cox   tty: some ICANON ...
2332
  			nr--;
bc5a5e3f4   Peter Hurley   n_tty: Don't wrap...
2333
  		tail++;
47afa7a5a   Alan Cox   tty: some ICANON ...
2334
2335
2336
2337
2338
2339
2340
  	}
  	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...
2341
  	struct n_tty_data *ldata = tty->disc_data;
47afa7a5a   Alan Cox   tty: some ICANON ...
2342
2343
2344
2345
2346
2347
  	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...
2348
  		down_write(&tty->termios_rwsem);
47afa7a5a   Alan Cox   tty: some ICANON ...
2349
  		if (L_ICANON(tty))
57c941212   Jiri Slaby   TTY: n_tty, propa...
2350
  			retval = inq_canon(ldata);
6d76bd261   Peter Hurley   n_tty: Make N_TTY...
2351
2352
2353
  		else
  			retval = read_cnt(ldata);
  		up_write(&tty->termios_rwsem);
47afa7a5a   Alan Cox   tty: some ICANON ...
2354
2355
2356
2357
2358
  		return put_user(retval, (unsigned int __user *) arg);
  	default:
  		return n_tty_ioctl_helper(tty, file, cmd, arg);
  	}
  }
27228732a   Peter Hurley   tty: Eliminate gl...
2359
  static struct tty_ldisc_ops n_tty_ops = {
e10cc1df1   Paul Fulghum   tty: add compat_i...
2360
2361
2362
2363
2364
  	.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...
2365
2366
  	.read            = n_tty_read,
  	.write           = n_tty_write,
e10cc1df1   Paul Fulghum   tty: add compat_i...
2367
2368
  	.ioctl           = n_tty_ioctl,
  	.set_termios     = n_tty_set_termios,
11a96d182   Alan Cox   tty: rename the r...
2369
  	.poll            = n_tty_poll,
e10cc1df1   Paul Fulghum   tty: add compat_i...
2370
  	.receive_buf     = n_tty_receive_buf,
f6c8dbe6e   Peter Hurley   n_tty: Encapsulat...
2371
  	.write_wakeup    = n_tty_write_wakeup,
24a89d1cb   Peter Hurley   tty: Make ldisc i...
2372
  	.receive_buf2	 = n_tty_receive_buf2,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2373
  };
572b9adbd   Rodolfo Giometti   ldisc n_tty: add ...
2374
2375
2376
2377
2378
  
  /**
   *	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...
2379
   *	Enables a 'subclass' line discipline to 'inherit' N_TTY methods.
572b9adbd   Rodolfo Giometti   ldisc n_tty: add ...
2380
2381
2382
2383
   */
  
  void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
  {
27228732a   Peter Hurley   tty: Eliminate gl...
2384
  	*ops = n_tty_ops;
572b9adbd   Rodolfo Giometti   ldisc n_tty: add ...
2385
2386
2387
2388
  	ops->owner = NULL;
  	ops->refcount = ops->flags = 0;
  }
  EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
27228732a   Peter Hurley   tty: Eliminate gl...
2389
2390
2391
2392
2393
  
  void __init n_tty_init(void)
  {
  	tty_register_ldisc(N_TTY, &n_tty_ops);
  }