Blame view
drivers/tty/n_tty.c
61.6 KB
e3b3d0f54 tty: add SPDX ide... |
1 |
// SPDX-License-Identifier: GPL-1.0+ |
1da177e4c Linux-2.6.12-rc2 |
2 3 |
/* * n_tty.c --- implements the N_TTY line discipline. |
4edf1827e n_tty: clean up o... |
4 |
* |
1da177e4c Linux-2.6.12-rc2 |
5 6 7 8 9 10 11 |
* This code used to be in tty_io.c, but things are getting hairy * enough that it made sense to split things off. (The N_TTY * processing has changed so much that it's hardly recognizable, * anyway...) * * Note that the open routine for N_TTY is guaranteed never to return * an error. This is because Linux will fall back to setting a line |
4edf1827e n_tty: clean up o... |
12 |
* to N_TTY if it can not switch to any other line discipline. |
1da177e4c Linux-2.6.12-rc2 |
13 14 |
* * Written by Theodore Ts'o, Copyright 1994. |
4edf1827e n_tty: clean up o... |
15 |
* |
1da177e4c Linux-2.6.12-rc2 |
16 17 |
* This file also contains code originally written by Linus Torvalds, * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994. |
4edf1827e n_tty: clean up o... |
18 |
* |
1da177e4c Linux-2.6.12-rc2 |
19 20 |
* Reduced memory usage for older ARM systems - Russell King. * |
4edf1827e n_tty: clean up o... |
21 |
* 2000/01/20 Fixed SMP locking on put_tty_queue using bits of |
1da177e4c Linux-2.6.12-rc2 |
22 23 24 25 26 |
* the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu> * who actually finally proved there really was a race. * * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to * waiting writing processes-Sapan Bhatia <sapan@corewars.org>. |
11a96d182 tty: rename the r... |
27 |
* Also fixed a bug in BLOCKING mode where n_tty_write returns |
1da177e4c Linux-2.6.12-rc2 |
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
* EAGAIN */ #include <linux/types.h> #include <linux/major.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/fcntl.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/timer.h> #include <linux/ctype.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/bitops.h> |
522ed7767 Audit: add TTY in... |
46 47 |
#include <linux/audit.h> #include <linux/file.h> |
300a6204b n_tty: clean up c... |
48 |
#include <linux/uaccess.h> |
572b9adbd ldisc n_tty: add ... |
49 |
#include <linux/module.h> |
593fb1ae4 pps: Move timesta... |
50 |
#include <linux/ratelimit.h> |
86e35aea4 n_tty: Fix build ... |
51 |
#include <linux/vmalloc.h> |
1da177e4c Linux-2.6.12-rc2 |
52 |
|
a5db48264 n_tty: update com... |
53 54 55 56 |
/* * Until this number of characters is queued in the xmit buffer, select will * return "we have room for writes". */ |
1da177e4c Linux-2.6.12-rc2 |
57 58 59 60 61 62 63 64 |
#define WAKEUP_CHARS 256 /* * This defines the low- and high-watermarks for throttling and * unthrottling the TTY driver. These watermarks are used for * controlling the space in the read buffer. */ #define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ |
bbd20759d drivers/tty: Remo... |
65 |
#define TTY_THRESHOLD_UNTHROTTLE 128 |
1da177e4c Linux-2.6.12-rc2 |
66 |
|
a88a69c91 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 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 n_tty: Line copy ... |
80 81 82 83 |
#undef N_TTY_TRACE #ifdef N_TTY_TRACE # define n_tty_trace(f, args...) trace_printk(f, ##args) #else |
a287885f1 n_tty: check prin... |
84 |
# define n_tty_trace(f, args...) no_printk(f, ##args) |
32f13521c n_tty: Line copy ... |
85 |
#endif |
70ece7a73 TTY: n_tty, add l... |
86 |
struct n_tty_data { |
fb7aa03db n_tty: Separate b... |
87 88 |
/* producer-published */ size_t read_head; |
70aca71f9 n_tty: Fix unorde... |
89 |
size_t commit_head; |
fb7aa03db n_tty: Separate b... |
90 |
size_t canon_head; |
9dfd16dde n_tty: Avoid fals... |
91 92 |
size_t echo_head; size_t echo_commit; |
1075a6e2d n_tty: Fix appare... |
93 |
size_t echo_mark; |
1bb9d5628 n_tty: Rename pro... |
94 |
DECLARE_BITMAP(char_map, 256); |
fb7aa03db n_tty: Separate b... |
95 96 |
/* private to n_tty_receive_overrun (single-threaded) */ |
53c5ee2cf TTY: move ldisc d... |
97 98 |
unsigned long overrun_time; int num_overrun; |
24a89d1cb tty: Make ldisc i... |
99 100 |
/* non-atomic */ bool no_room; |
fb7aa03db n_tty: Separate b... |
101 |
/* must hold exclusive termios_rwsem to reset these */ |
53c5ee2cf TTY: move ldisc d... |
102 |
unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1; |
4d0ed1827 n_tty: Fix buffer... |
103 |
unsigned char push:1; |
3fe780b37 TTY: move ldisc d... |
104 |
|
fb7aa03db n_tty: Separate b... |
105 |
/* shared by producer and consumer */ |
20bafb3d2 n_tty: Move buffe... |
106 |
char read_buf[N_TTY_BUF_SIZE]; |
3fe780b37 TTY: move ldisc d... |
107 |
DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE); |
20bafb3d2 n_tty: Move buffe... |
108 |
unsigned char echo_buf[N_TTY_BUF_SIZE]; |
ba2e68ac6 TTY: move ldisc d... |
109 |
|
fb7aa03db n_tty: Separate b... |
110 111 |
/* consumer-published */ size_t read_tail; |
40d5e0905 n_tty: Fix EOF pu... |
112 |
size_t line_start; |
fb7aa03db n_tty: Separate b... |
113 |
|
fb7aa03db n_tty: Separate b... |
114 115 |
/* protected by output lock */ unsigned int column; |
ba2e68ac6 TTY: move ldisc d... |
116 |
unsigned int canon_column; |
9dfd16dde n_tty: Avoid fals... |
117 |
size_t echo_tail; |
bddc7152f TTY: move ldisc d... |
118 119 120 |
struct mutex atomic_read_lock; struct mutex output_lock; |
70ece7a73 TTY: n_tty, add l... |
121 |
}; |
3d63b7e4a n_tty: Fix stall ... |
122 |
#define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1)) |
ce74117a1 n_tty: Get read_c... |
123 124 |
static inline size_t read_cnt(struct n_tty_data *ldata) { |
a2f73be8e n_tty: Remove rea... |
125 |
return ldata->read_head - ldata->read_tail; |
ce74117a1 n_tty: Get read_c... |
126 |
} |
bc5a5e3f4 n_tty: Don't wrap... |
127 128 129 130 131 132 133 134 135 |
static inline unsigned char read_buf(struct n_tty_data *ldata, size_t i) { return ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)]; } static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i) { return &ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)]; } |
addaebccf n_tty: Use separa... |
136 137 |
static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i) { |
ebec3f8f5 n_tty: Access ech... |
138 |
smp_rmb(); /* Matches smp_wmb() in add_echo_byte(). */ |
addaebccf n_tty: Use separa... |
139 140 141 142 143 144 145 |
return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)]; } static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i) { return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)]; } |
b97b3d9fb tty: wipe buffer ... |
146 147 148 149 150 151 152 153 154 |
/* If we are not echoing the data, perhaps this is a secret so erase it */ static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size) { bool icanon = !!L_ICANON(tty); bool no_echo = !L_ECHO(tty); if (icanon && no_echo) memset(buffer, 0x00, size); } |
679e7c299 n_tty: Uninline t... |
155 156 |
static int tty_copy_to_user(struct tty_struct *tty, void __user *to, size_t tail, size_t n) |
72586c606 n_tty: Fix auditi... |
157 158 |
{ struct n_tty_data *ldata = tty->disc_data; |
679e7c299 n_tty: Uninline t... |
159 |
size_t size = N_TTY_BUF_SIZE - tail; |
b97b3d9fb tty: wipe buffer ... |
160 |
void *from = read_buf_addr(ldata, tail); |
679e7c299 n_tty: Uninline t... |
161 162 163 |
int uncopied; if (n > size) { |
309426ae6 tty: audit: Remov... |
164 |
tty_audit_add_data(tty, from, size); |
679e7c299 n_tty: Uninline t... |
165 |
uncopied = copy_to_user(to, from, size); |
b97b3d9fb tty: wipe buffer ... |
166 |
zero_buffer(tty, from, size - uncopied); |
679e7c299 n_tty: Uninline t... |
167 168 169 170 171 172 |
if (uncopied) return uncopied; to += size; n -= size; from = ldata->read_buf; } |
72586c606 n_tty: Fix auditi... |
173 |
|
309426ae6 tty: audit: Remov... |
174 |
tty_audit_add_data(tty, from, n); |
b97b3d9fb tty: wipe buffer ... |
175 176 177 |
uncopied = copy_to_user(to, from, n); zero_buffer(tty, from, n - uncopied); return uncopied; |
72586c606 n_tty: Fix auditi... |
178 |
} |
24a89d1cb tty: Make ldisc i... |
179 |
/** |
2c5dc4641 n_tty: Eliminate ... |
180 |
* n_tty_kick_worker - start input worker (if required) |
24a89d1cb tty: Make ldisc i... |
181 182 |
* @tty: terminal * |
2c5dc4641 n_tty: Eliminate ... |
183 |
* Re-schedules the flip buffer work if it may have stopped |
24a89d1cb tty: Make ldisc i... |
184 |
* |
6d76bd261 n_tty: Make N_TTY... |
185 186 187 188 |
* Caller holds exclusive termios_rwsem * or * n_tty_read()/consumer path: * holds non-exclusive termios_rwsem |
24a89d1cb tty: Make ldisc i... |
189 |
*/ |
2c5dc4641 n_tty: Eliminate ... |
190 |
static void n_tty_kick_worker(struct tty_struct *tty) |
7879a9f9f n_tty: Buffer wor... |
191 |
{ |
24a89d1cb tty: Make ldisc i... |
192 |
struct n_tty_data *ldata = tty->disc_data; |
2c5dc4641 n_tty: Eliminate ... |
193 194 |
/* Did the input worker stop? Restart it */ if (unlikely(ldata->no_room)) { |
24a89d1cb tty: Make ldisc i... |
195 |
ldata->no_room = 0; |
ecbbfd44a TTY: move tty buf... |
196 |
WARN_RATELIMIT(tty->port->itty == NULL, |
cadf74869 tty: add missing ... |
197 198 |
"scheduling with invalid itty "); |
21622939f tty: Add diagnost... |
199 200 201 202 203 204 205 |
/* see if ldisc has been killed - if so, this means that * even though the ldisc has been halted and ->buf.work * cancelled, ->buf.work is about to be rescheduled */ WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags), "scheduling buffer work for halted ldisc "); |
e176058f0 tty: Abstract tty... |
206 |
tty_buffer_restart_work(tty->port); |
ecbbfd44a TTY: move tty buf... |
207 |
} |
55db4c64e Revert "tty: make... |
208 |
} |
9a4aec2dd n_tty: Move chars... |
209 210 211 212 213 214 |
static ssize_t chars_in_buffer(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; ssize_t n = 0; if (!ldata->icanon) |
70aca71f9 n_tty: Fix unorde... |
215 |
n = ldata->commit_head - ldata->read_tail; |
9a4aec2dd n_tty: Move chars... |
216 217 218 219 |
else n = ldata->canon_head - ldata->read_tail; return n; } |
ee0bab83c n_tty: Move n_tty... |
220 221 222 223 224 225 226 227 228 229 230 |
/** * n_tty_write_wakeup - asynchronous I/O notifier * @tty: tty device * * Required for the ptys, serial driver etc. since processes * that attach themselves to the master and rely on ASYNC * IO must be woken up */ static void n_tty_write_wakeup(struct tty_struct *tty) { |
7bccc3654 n_tty: Fix stuck ... |
231 232 |
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); kill_fasync(&tty->fasync, SIGIO, POLL_OUT); |
ee0bab83c n_tty: Move n_tty... |
233 |
} |
4a23a4df5 n_tty: Factor 're... |
234 |
static void n_tty_check_throttle(struct tty_struct *tty) |
6367ca72f n_tty: Factor thr... |
235 |
{ |
a342846f9 n_tty: Fix thrott... |
236 |
struct n_tty_data *ldata = tty->disc_data; |
6367ca72f n_tty: Factor thr... |
237 238 239 240 241 |
/* * Check the remaining room for the input canonicalization * mode. We don't want to throttle the driver if we're in * canonical mode and don't have a newline yet! */ |
a342846f9 n_tty: Fix thrott... |
242 243 |
if (ldata->icanon && ldata->canon_head == ldata->read_tail) return; |
6367ca72f n_tty: Factor thr... |
244 245 246 |
while (1) { int throttled; tty_set_flow_change(tty, TTY_THROTTLE_SAFE); |
5e28cca15 n_tty: Simplify t... |
247 |
if (N_TTY_BUF_SIZE - read_cnt(ldata) >= TTY_THRESHOLD_THROTTLE) |
6367ca72f n_tty: Factor thr... |
248 249 250 251 252 253 254 |
break; throttled = tty_throttle_safe(tty); if (!throttled) break; } __tty_set_flow_change(tty, 0); } |
4b293492a n_tty: Un-inline ... |
255 |
static void n_tty_check_unthrottle(struct tty_struct *tty) |
6367ca72f n_tty: Factor thr... |
256 |
{ |
6d27a63ca n_tty: Fix unsafe... |
257 |
if (tty->driver->type == TTY_DRIVER_TYPE_PTY) { |
3afb1b394 n_tty: Special ca... |
258 259 |
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) return; |
2c5dc4641 n_tty: Eliminate ... |
260 |
n_tty_kick_worker(tty); |
6d27a63ca n_tty: Fix unsafe... |
261 |
tty_wakeup(tty->link); |
3afb1b394 n_tty: Special ca... |
262 263 |
return; } |
6367ca72f n_tty: Factor thr... |
264 265 266 267 268 269 270 271 272 273 274 275 276 |
/* If there is enough space in the read buffer now, let the * low-level driver know. We use chars_in_buffer() to * check the buffer, as it now knows about canonical mode. * Otherwise, if the driver is throttled and the line is * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode, * we won't get any more characters. */ while (1) { int unthrottled; tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE); if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) break; |
2c5dc4641 n_tty: Eliminate ... |
277 |
n_tty_kick_worker(tty); |
6367ca72f n_tty: Factor thr... |
278 279 280 281 282 283 |
unthrottled = tty_unthrottle_safe(tty); if (!unthrottled) break; } __tty_set_flow_change(tty, 0); } |
17b820606 tty: Minor tidyup... |
284 285 286 |
/** * put_tty_queue - add character to tty * @c: character |
57c941212 TTY: n_tty, propa... |
287 |
* @ldata: n_tty data |
17b820606 tty: Minor tidyup... |
288 |
* |
6d76bd261 n_tty: Make N_TTY... |
289 290 291 292 |
* Add a character to the tty read_buf queue. * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem |
17b820606 tty: Minor tidyup... |
293 |
*/ |
19e2ad6a0 n_tty: Remove ove... |
294 |
static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) |
1da177e4c Linux-2.6.12-rc2 |
295 |
{ |
8bfbe2de7 n_tty: Fix read_b... |
296 297 |
*read_buf_addr(ldata, ldata->read_head) = c; ldata->read_head++; |
1da177e4c Linux-2.6.12-rc2 |
298 299 300 |
} /** |
1da177e4c Linux-2.6.12-rc2 |
301 302 303 |
* reset_buffer_flags - reset buffer state * @tty: terminal to reset * |
25518c68b n_tty: Correct un... |
304 305 |
* Reset the read buffer counters and clear the flags. * Called from n_tty_open() and n_tty_flush_buffer(). |
17b820606 tty: Minor tidyup... |
306 |
* |
6d76bd261 n_tty: Make N_TTY... |
307 308 |
* Locking: caller holds exclusive termios_rwsem * (or locking is not required) |
1da177e4c Linux-2.6.12-rc2 |
309 |
*/ |
a88a69c91 n_tty: Fix loss o... |
310 |
|
b66f4fa50 n_tty: Fully init... |
311 |
static void reset_buffer_flags(struct n_tty_data *ldata) |
1da177e4c Linux-2.6.12-rc2 |
312 |
{ |
a73d3d698 n_tty: Replace ca... |
313 |
ldata->read_head = ldata->canon_head = ldata->read_tail = 0; |
70aca71f9 n_tty: Fix unorde... |
314 |
ldata->commit_head = 0; |
40d5e0905 n_tty: Fix EOF pu... |
315 |
ldata->line_start = 0; |
a88a69c91 n_tty: Fix loss o... |
316 |
|
a73d3d698 n_tty: Replace ca... |
317 |
ldata->erasing = 0; |
3fe780b37 TTY: move ldisc d... |
318 |
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); |
4d0ed1827 n_tty: Fix buffer... |
319 |
ldata->push = 0; |
1da177e4c Linux-2.6.12-rc2 |
320 |
} |
a30737ab7 n_tty: Factor pac... |
321 322 323 |
static void n_tty_packet_mode_flush(struct tty_struct *tty) { unsigned long flags; |
a30737ab7 n_tty: Factor pac... |
324 |
if (tty->link->packet) { |
54e8e5fca pty: Don't claim ... |
325 |
spin_lock_irqsave(&tty->ctrl_lock, flags); |
a30737ab7 n_tty: Factor pac... |
326 |
tty->ctrl_status |= TIOCPKT_FLUSHREAD; |
54e8e5fca pty: Don't claim ... |
327 |
spin_unlock_irqrestore(&tty->ctrl_lock, flags); |
e81107d4c tty: fix stall ca... |
328 |
wake_up_interruptible(&tty->link->read_wait); |
a30737ab7 n_tty: Factor pac... |
329 |
} |
a30737ab7 n_tty: Factor pac... |
330 |
} |
1da177e4c Linux-2.6.12-rc2 |
331 332 333 334 |
/** * n_tty_flush_buffer - clean input queue * @tty: terminal device * |
25518c68b n_tty: Correct un... |
335 336 337 |
* Flush the input buffer. Called when the tty layer wants the * buffer flushed (eg at hangup) or when the N_TTY line discipline * internally has to clean the pending queue (for example some signals). |
1da177e4c Linux-2.6.12-rc2 |
338 |
* |
6d76bd261 n_tty: Make N_TTY... |
339 340 341 342 |
* Holds termios_rwsem to exclude producer/consumer while * buffer indices are reset. * * Locking: ctrl_lock, exclusive termios_rwsem |
1da177e4c Linux-2.6.12-rc2 |
343 |
*/ |
4edf1827e n_tty: clean up o... |
344 345 |
static void n_tty_flush_buffer(struct tty_struct *tty) |
1da177e4c Linux-2.6.12-rc2 |
346 |
{ |
6d76bd261 n_tty: Make N_TTY... |
347 |
down_write(&tty->termios_rwsem); |
b66f4fa50 n_tty: Fully init... |
348 |
reset_buffer_flags(tty->disc_data); |
2c5dc4641 n_tty: Eliminate ... |
349 |
n_tty_kick_worker(tty); |
4edf1827e n_tty: clean up o... |
350 |
|
a30737ab7 n_tty: Factor pac... |
351 352 |
if (tty->link) n_tty_packet_mode_flush(tty); |
6d76bd261 n_tty: Make N_TTY... |
353 |
up_write(&tty->termios_rwsem); |
1da177e4c Linux-2.6.12-rc2 |
354 |
} |
6d76bd261 n_tty: Make N_TTY... |
355 |
/** |
1da177e4c Linux-2.6.12-rc2 |
356 357 358 359 360 361 362 |
* is_utf8_continuation - utf8 multibyte check * @c: byte to check * * Returns true if the utf8 character 'c' is a multibyte continuation * character. We use this to correctly compute the on screen size * of the character when printing */ |
4edf1827e n_tty: clean up o... |
363 |
|
1da177e4c Linux-2.6.12-rc2 |
364 365 366 367 368 369 370 371 372 373 374 375 |
static inline int is_utf8_continuation(unsigned char c) { return (c & 0xc0) == 0x80; } /** * is_continuation - multibyte check * @c: byte to check * * Returns true if the utf8 character 'c' is a multibyte continuation * character and the terminal is in unicode mode. */ |
4edf1827e n_tty: clean up o... |
376 |
|
1da177e4c Linux-2.6.12-rc2 |
377 378 379 380 381 382 |
static inline int is_continuation(unsigned char c, struct tty_struct *tty) { return I_IUTF8(tty) && is_utf8_continuation(c); } /** |
a88a69c91 n_tty: Fix loss o... |
383 |
* do_output_char - output one character |
1da177e4c Linux-2.6.12-rc2 |
384 385 |
* @c: character (or partial unicode symbol) * @tty: terminal device |
a88a69c91 n_tty: Fix loss o... |
386 |
* @space: space available in tty driver write buffer |
1da177e4c Linux-2.6.12-rc2 |
387 |
* |
a88a69c91 n_tty: Fix loss o... |
388 389 |
* This is a helper function that handles one output character * (including special characters like TAB, CR, LF, etc.), |
ee5aa7b8b n_tty: honor opos... |
390 391 |
* doing OPOST processing and putting the results in the * tty driver's write buffer. |
a88a69c91 n_tty: Fix loss o... |
392 393 394 395 |
* * Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY * and NLDLY. They simply aren't relevant in the world today. * If you ever need them, add them here. |
1da177e4c Linux-2.6.12-rc2 |
396 |
* |
a88a69c91 n_tty: Fix loss o... |
397 398 399 400 401 |
* Returns the number of bytes of buffer space used or -1 if * no space left. * * Locking: should be called under the output_lock to protect * the column state and space left in the buffer |
1da177e4c Linux-2.6.12-rc2 |
402 |
*/ |
4edf1827e n_tty: clean up o... |
403 |
|
a88a69c91 n_tty: Fix loss o... |
404 |
static int do_output_char(unsigned char c, struct tty_struct *tty, int space) |
1da177e4c Linux-2.6.12-rc2 |
405 |
{ |
53c5ee2cf TTY: move ldisc d... |
406 |
struct n_tty_data *ldata = tty->disc_data; |
a88a69c91 n_tty: Fix loss o... |
407 |
int spaces; |
1da177e4c Linux-2.6.12-rc2 |
408 |
|
1da177e4c Linux-2.6.12-rc2 |
409 410 |
if (!space) return -1; |
300a6204b n_tty: clean up c... |
411 |
|
a88a69c91 n_tty: Fix loss o... |
412 413 414 415 |
switch (c) { case ' ': if (O_ONLRET(tty)) |
53c5ee2cf TTY: move ldisc d... |
416 |
ldata->column = 0; |
a88a69c91 n_tty: Fix loss o... |
417 418 419 |
if (O_ONLCR(tty)) { if (space < 2) return -1; |
ba2e68ac6 TTY: move ldisc d... |
420 |
ldata->canon_column = ldata->column = 0; |
37f81fa1f n_tty: do O_ONLCR... |
421 422 |
tty->ops->write(tty, "\r ", 2); |
a88a69c91 n_tty: Fix loss o... |
423 424 |
return 2; } |
ba2e68ac6 TTY: move ldisc d... |
425 |
ldata->canon_column = ldata->column; |
a88a69c91 n_tty: Fix loss o... |
426 427 |
break; case '\r': |
53c5ee2cf TTY: move ldisc d... |
428 |
if (O_ONOCR(tty) && ldata->column == 0) |
a88a69c91 n_tty: Fix loss o... |
429 430 431 432 433 |
return 0; if (O_OCRNL(tty)) { c = ' '; if (O_ONLRET(tty)) |
ba2e68ac6 TTY: move ldisc d... |
434 |
ldata->canon_column = ldata->column = 0; |
1da177e4c Linux-2.6.12-rc2 |
435 |
break; |
a88a69c91 n_tty: Fix loss o... |
436 |
} |
ba2e68ac6 TTY: move ldisc d... |
437 |
ldata->canon_column = ldata->column = 0; |
a88a69c91 n_tty: Fix loss o... |
438 439 |
break; case '\t': |
53c5ee2cf TTY: move ldisc d... |
440 |
spaces = 8 - (ldata->column & 7); |
a88a69c91 n_tty: Fix loss o... |
441 442 443 |
if (O_TABDLY(tty) == XTABS) { if (space < spaces) return -1; |
53c5ee2cf TTY: move ldisc d... |
444 |
ldata->column += spaces; |
a88a69c91 n_tty: Fix loss o... |
445 446 |
tty->ops->write(tty, " ", spaces); return spaces; |
1da177e4c Linux-2.6.12-rc2 |
447 |
} |
53c5ee2cf TTY: move ldisc d... |
448 |
ldata->column += spaces; |
a88a69c91 n_tty: Fix loss o... |
449 450 |
break; case '\b': |
53c5ee2cf TTY: move ldisc d... |
451 452 |
if (ldata->column > 0) ldata->column--; |
a88a69c91 n_tty: Fix loss o... |
453 454 |
break; default: |
a59c0d6f1 n_tty: Fix handli... |
455 456 457 458 |
if (!iscntrl(c)) { if (O_OLCUC(tty)) c = toupper(c); if (!is_continuation(c, tty)) |
53c5ee2cf TTY: move ldisc d... |
459 |
ldata->column++; |
a59c0d6f1 n_tty: Fix handli... |
460 |
} |
a88a69c91 n_tty: Fix loss o... |
461 |
break; |
1da177e4c Linux-2.6.12-rc2 |
462 |
} |
a88a69c91 n_tty: Fix loss o... |
463 |
|
f34d7a5b7 tty: The big oper... |
464 |
tty_put_char(tty, c); |
a88a69c91 n_tty: Fix loss o... |
465 466 467 468 469 470 471 472 |
return 1; } /** * process_output - output post processor * @c: character (or partial unicode symbol) * @tty: terminal device * |
ee5aa7b8b n_tty: honor opos... |
473 474 475 |
* Output one character with OPOST processing. * Returns -1 when the output device is full and the character * must be retried. |
a88a69c91 n_tty: Fix loss o... |
476 477 478 479 480 481 482 483 |
* * Locking: output_lock to protect column state and space left * (also, this is called from n_tty_write under the * tty layer write lock) */ static int process_output(unsigned char c, struct tty_struct *tty) { |
bddc7152f TTY: move ldisc d... |
484 |
struct n_tty_data *ldata = tty->disc_data; |
a88a69c91 n_tty: Fix loss o... |
485 |
int space, retval; |
bddc7152f TTY: move ldisc d... |
486 |
mutex_lock(&ldata->output_lock); |
a88a69c91 n_tty: Fix loss o... |
487 488 489 |
space = tty_write_room(tty); retval = do_output_char(c, tty, space); |
bddc7152f TTY: move ldisc d... |
490 |
mutex_unlock(&ldata->output_lock); |
a88a69c91 n_tty: Fix loss o... |
491 492 493 494 |
if (retval < 0) return -1; else return 0; |
1da177e4c Linux-2.6.12-rc2 |
495 496 497 |
} /** |
a88a69c91 n_tty: Fix loss o... |
498 |
* process_output_block - block post processor |
1da177e4c Linux-2.6.12-rc2 |
499 |
* @tty: terminal device |
ee5aa7b8b n_tty: honor opos... |
500 501 502 503 504 |
* @buf: character buffer * @nr: number of bytes to output * * Output a block of characters with OPOST processing. * Returns the number of characters output. |
1da177e4c Linux-2.6.12-rc2 |
505 506 507 508 509 510 |
* * This path is used to speed up block console writes, among other * things when processing blocks of output data. It handles only * the simple cases normally found and helps to generate blocks of * symbols for the console driver and thus improve performance. * |
a88a69c91 n_tty: Fix loss o... |
511 512 513 |
* Locking: output_lock to protect column state and space left * (also, this is called from n_tty_write under the * tty layer write lock) |
1da177e4c Linux-2.6.12-rc2 |
514 |
*/ |
4edf1827e n_tty: clean up o... |
515 |
|
a88a69c91 n_tty: Fix loss o... |
516 517 |
static ssize_t process_output_block(struct tty_struct *tty, const unsigned char *buf, unsigned int nr) |
1da177e4c Linux-2.6.12-rc2 |
518 |
{ |
53c5ee2cf TTY: move ldisc d... |
519 |
struct n_tty_data *ldata = tty->disc_data; |
1da177e4c Linux-2.6.12-rc2 |
520 |
int space; |
bbd20759d drivers/tty: Remo... |
521 |
int i; |
1da177e4c Linux-2.6.12-rc2 |
522 |
const unsigned char *cp; |
bddc7152f TTY: move ldisc d... |
523 |
mutex_lock(&ldata->output_lock); |
a88a69c91 n_tty: Fix loss o... |
524 |
|
f34d7a5b7 tty: The big oper... |
525 |
space = tty_write_room(tty); |
9ef8927f4 n_tty: check for ... |
526 |
if (space <= 0) { |
bddc7152f TTY: move ldisc d... |
527 |
mutex_unlock(&ldata->output_lock); |
9ef8927f4 n_tty: check for ... |
528 |
return space; |
a88a69c91 n_tty: Fix loss o... |
529 |
} |
1da177e4c Linux-2.6.12-rc2 |
530 531 532 533 |
if (nr > space) nr = space; for (i = 0, cp = buf; i < nr; i++, cp++) { |
a59c0d6f1 n_tty: Fix handli... |
534 535 536 |
unsigned char c = *cp; switch (c) { |
1da177e4c Linux-2.6.12-rc2 |
537 538 539 |
case ' ': if (O_ONLRET(tty)) |
53c5ee2cf TTY: move ldisc d... |
540 |
ldata->column = 0; |
1da177e4c Linux-2.6.12-rc2 |
541 542 |
if (O_ONLCR(tty)) goto break_out; |
ba2e68ac6 TTY: move ldisc d... |
543 |
ldata->canon_column = ldata->column; |
1da177e4c Linux-2.6.12-rc2 |
544 545 |
break; case '\r': |
53c5ee2cf TTY: move ldisc d... |
546 |
if (O_ONOCR(tty) && ldata->column == 0) |
1da177e4c Linux-2.6.12-rc2 |
547 548 549 |
goto break_out; if (O_OCRNL(tty)) goto break_out; |
ba2e68ac6 TTY: move ldisc d... |
550 |
ldata->canon_column = ldata->column = 0; |
1da177e4c Linux-2.6.12-rc2 |
551 552 553 554 |
break; case '\t': goto break_out; case '\b': |
53c5ee2cf TTY: move ldisc d... |
555 556 |
if (ldata->column > 0) ldata->column--; |
1da177e4c Linux-2.6.12-rc2 |
557 558 |
break; default: |
a59c0d6f1 n_tty: Fix handli... |
559 560 561 562 |
if (!iscntrl(c)) { if (O_OLCUC(tty)) goto break_out; if (!is_continuation(c, tty)) |
53c5ee2cf TTY: move ldisc d... |
563 |
ldata->column++; |
a59c0d6f1 n_tty: Fix handli... |
564 |
} |
1da177e4c Linux-2.6.12-rc2 |
565 566 567 568 |
break; } } break_out: |
f34d7a5b7 tty: The big oper... |
569 |
i = tty->ops->write(tty, buf, i); |
a88a69c91 n_tty: Fix loss o... |
570 |
|
bddc7152f TTY: move ldisc d... |
571 |
mutex_unlock(&ldata->output_lock); |
1da177e4c Linux-2.6.12-rc2 |
572 573 |
return i; } |
a88a69c91 n_tty: Fix loss o... |
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 |
/** * process_echoes - write pending echo characters * @tty: terminal device * * Write previously buffered echo (and other ldisc-generated) * characters to the tty. * * Characters generated by the ldisc (including echoes) need to * be buffered because the driver's write buffer can fill during * heavy program output. Echoing straight to the driver will * often fail under these conditions, causing lost characters and * resulting mismatches of ldisc state information. * * Since the ldisc state must represent the characters actually sent * to the driver at the time of the write, operations like certain * changes in column state are also saved in the buffer and executed * here. * * A circular fifo buffer is used so that the most recent characters * are prioritized. Also, when control characters are echoed with a * prefixed "^", the pair is treated atomically and thus not separated. * |
019ebdf9f n_tty: Eliminate ... |
596 |
* Locking: callers must hold output_lock |
a88a69c91 n_tty: Fix loss o... |
597 |
*/ |
bc5b1ec58 n_tty: Only flush... |
598 |
static size_t __process_echoes(struct tty_struct *tty) |
a88a69c91 n_tty: Fix loss o... |
599 |
{ |
53c5ee2cf TTY: move ldisc d... |
600 |
struct n_tty_data *ldata = tty->disc_data; |
bc5b1ec58 n_tty: Only flush... |
601 |
int space, old_space; |
addaebccf n_tty: Use separa... |
602 |
size_t tail; |
a88a69c91 n_tty: Fix loss o... |
603 |
unsigned char c; |
a88a69c91 n_tty: Fix loss o... |
604 |
|
bc5b1ec58 n_tty: Only flush... |
605 |
old_space = space = tty_write_room(tty); |
a88a69c91 n_tty: Fix loss o... |
606 |
|
addaebccf n_tty: Use separa... |
607 |
tail = ldata->echo_tail; |
ebec3f8f5 n_tty: Access ech... |
608 |
while (MASK(ldata->echo_commit) != MASK(tail)) { |
addaebccf n_tty: Use separa... |
609 |
c = echo_buf(ldata, tail); |
a88a69c91 n_tty: Fix loss o... |
610 611 |
if (c == ECHO_OP_START) { unsigned char op; |
a88a69c91 n_tty: Fix loss o... |
612 613 614 |
int no_space_left = 0; /* |
ebec3f8f5 n_tty: Access ech... |
615 616 617 618 619 620 621 |
* Since add_echo_byte() is called without holding * output_lock, we might see only portion of multi-byte * operation. */ if (MASK(ldata->echo_commit) == MASK(tail + 1)) goto not_yet_stored; /* |
a88a69c91 n_tty: Fix loss o... |
622 623 624 625 |
* If the buffer byte is the start of a multi-byte * operation, get the next byte, which is either the * op code or a control character value. */ |
addaebccf n_tty: Use separa... |
626 |
op = echo_buf(ldata, tail + 1); |
300a6204b n_tty: clean up c... |
627 |
|
a88a69c91 n_tty: Fix loss o... |
628 |
switch (op) { |
e24cd4e6d n_tty: Distribute... |
629 |
case ECHO_OP_ERASE_TAB: { |
a88a69c91 n_tty: Fix loss o... |
630 |
unsigned int num_chars, num_bs; |
ebec3f8f5 n_tty: Access ech... |
631 632 |
if (MASK(ldata->echo_commit) == MASK(tail + 2)) goto not_yet_stored; |
addaebccf n_tty: Use separa... |
633 |
num_chars = echo_buf(ldata, tail + 2); |
a88a69c91 n_tty: Fix loss o... |
634 635 636 637 638 639 640 641 642 643 644 645 |
/* * Determine how many columns to go back * in order to erase the tab. * This depends on the number of columns * used by other characters within the tab * area. If this (modulo 8) count is from * the start of input rather than from a * previous tab, we offset by canon column. * Otherwise, tab spacing is normal. */ if (!(num_chars & 0x80)) |
ba2e68ac6 TTY: move ldisc d... |
646 |
num_chars += ldata->canon_column; |
a88a69c91 n_tty: Fix loss o... |
647 648 649 650 651 652 653 654 655 |
num_bs = 8 - (num_chars & 7); if (num_bs > space) { no_space_left = 1; break; } space -= num_bs; while (num_bs--) { tty_put_char(tty, '\b'); |
53c5ee2cf TTY: move ldisc d... |
656 657 |
if (ldata->column > 0) ldata->column--; |
a88a69c91 n_tty: Fix loss o... |
658 |
} |
addaebccf n_tty: Use separa... |
659 |
tail += 3; |
a88a69c91 n_tty: Fix loss o... |
660 |
break; |
e24cd4e6d n_tty: Distribute... |
661 |
} |
a88a69c91 n_tty: Fix loss o... |
662 |
case ECHO_OP_SET_CANON_COL: |
ba2e68ac6 TTY: move ldisc d... |
663 |
ldata->canon_column = ldata->column; |
addaebccf n_tty: Use separa... |
664 |
tail += 2; |
a88a69c91 n_tty: Fix loss o... |
665 666 667 |
break; case ECHO_OP_MOVE_BACK_COL: |
53c5ee2cf TTY: move ldisc d... |
668 669 |
if (ldata->column > 0) ldata->column--; |
addaebccf n_tty: Use separa... |
670 |
tail += 2; |
a88a69c91 n_tty: Fix loss o... |
671 672 673 674 675 676 677 678 679 |
break; case ECHO_OP_START: /* This is an escaped echo op start code */ if (!space) { no_space_left = 1; break; } tty_put_char(tty, ECHO_OP_START); |
53c5ee2cf TTY: move ldisc d... |
680 |
ldata->column++; |
a88a69c91 n_tty: Fix loss o... |
681 |
space--; |
addaebccf n_tty: Use separa... |
682 |
tail += 2; |
a88a69c91 n_tty: Fix loss o... |
683 684 685 |
break; default: |
a88a69c91 n_tty: Fix loss o... |
686 |
/* |
62b263585 n_tty: move echoc... |
687 688 689 690 691 692 693 |
* If the op is not a special byte code, * it is a ctrl char tagged to be echoed * as "^X" (where X is the letter * representing the control char). * Note that we must ensure there is * enough space for the whole ctrl pair. * |
a88a69c91 n_tty: Fix loss o... |
694 |
*/ |
62b263585 n_tty: move echoc... |
695 696 697 698 699 700 |
if (space < 2) { no_space_left = 1; break; } tty_put_char(tty, '^'); tty_put_char(tty, op ^ 0100); |
53c5ee2cf TTY: move ldisc d... |
701 |
ldata->column += 2; |
62b263585 n_tty: move echoc... |
702 |
space -= 2; |
addaebccf n_tty: Use separa... |
703 |
tail += 2; |
a88a69c91 n_tty: Fix loss o... |
704 705 706 707 708 |
} if (no_space_left) break; } else { |
582f55907 tty: Remove TTY_H... |
709 |
if (O_OPOST(tty)) { |
ee5aa7b8b n_tty: honor opos... |
710 711 712 713 714 715 716 717 718 719 |
int retval = do_output_char(c, tty, space); if (retval < 0) break; space -= retval; } else { if (!space) break; tty_put_char(tty, c); space -= 1; } |
addaebccf n_tty: Use separa... |
720 |
tail += 1; |
a88a69c91 n_tty: Fix loss o... |
721 |
} |
a88a69c91 n_tty: Fix loss o... |
722 |
} |
cbfd0340a n_tty: Process ec... |
723 724 725 |
/* If the echo buffer is nearly full (so that the possibility exists * of echo overrun before the next commit), then discard enough * data at the tail to prevent a subsequent overrun */ |
ebec3f8f5 n_tty: Access ech... |
726 727 |
while (ldata->echo_commit > tail && ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { |
c476f6584 tty: incorrect te... |
728 |
if (echo_buf(ldata, tail) == ECHO_OP_START) { |
6f2225363 n_tty: Fix echo o... |
729 |
if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB) |
cbfd0340a n_tty: Process ec... |
730 731 732 733 734 735 |
tail += 3; else tail += 2; } else tail++; } |
ebec3f8f5 n_tty: Access ech... |
736 |
not_yet_stored: |
addaebccf n_tty: Use separa... |
737 |
ldata->echo_tail = tail; |
bc5b1ec58 n_tty: Only flush... |
738 |
return old_space - space; |
019ebdf9f n_tty: Eliminate ... |
739 740 741 742 743 |
} static void commit_echoes(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; |
bc5b1ec58 n_tty: Only flush... |
744 |
size_t nr, old, echoed; |
cbfd0340a n_tty: Process ec... |
745 |
size_t head; |
ebec3f8f5 n_tty: Access ech... |
746 |
mutex_lock(&ldata->output_lock); |
cbfd0340a n_tty: Process ec... |
747 |
head = ldata->echo_head; |
1075a6e2d n_tty: Fix appare... |
748 |
ldata->echo_mark = head; |
cbfd0340a n_tty: Process ec... |
749 750 751 752 753 754 |
old = ldata->echo_commit - ldata->echo_tail; /* Process committed echoes if the accumulated # of bytes * is over the threshold (and try again each time another * block is accumulated) */ nr = head - ldata->echo_tail; |
ebec3f8f5 n_tty: Access ech... |
755 756 757 |
if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK)) { mutex_unlock(&ldata->output_lock); |
cbfd0340a n_tty: Process ec... |
758 |
return; |
ebec3f8f5 n_tty: Access ech... |
759 |
} |
a88a69c91 n_tty: Fix loss o... |
760 |
|
cbfd0340a n_tty: Process ec... |
761 |
ldata->echo_commit = head; |
bc5b1ec58 n_tty: Only flush... |
762 |
echoed = __process_echoes(tty); |
bddc7152f TTY: move ldisc d... |
763 |
mutex_unlock(&ldata->output_lock); |
a88a69c91 n_tty: Fix loss o... |
764 |
|
bc5b1ec58 n_tty: Only flush... |
765 |
if (echoed && tty->ops->flush_chars) |
a88a69c91 n_tty: Fix loss o... |
766 767 |
tty->ops->flush_chars(tty); } |
019ebdf9f n_tty: Eliminate ... |
768 |
static void process_echoes(struct tty_struct *tty) |
17bd79074 n_tty: Remove ech... |
769 770 |
{ struct n_tty_data *ldata = tty->disc_data; |
bc5b1ec58 n_tty: Only flush... |
771 |
size_t echoed; |
17bd79074 n_tty: Remove ech... |
772 |
|
e2613be50 n_tty: Fix stale ... |
773 |
if (ldata->echo_mark == ldata->echo_tail) |
019ebdf9f n_tty: Eliminate ... |
774 775 776 |
return; mutex_lock(&ldata->output_lock); |
1075a6e2d n_tty: Fix appare... |
777 |
ldata->echo_commit = ldata->echo_mark; |
bc5b1ec58 n_tty: Only flush... |
778 |
echoed = __process_echoes(tty); |
019ebdf9f n_tty: Eliminate ... |
779 |
mutex_unlock(&ldata->output_lock); |
bc5b1ec58 n_tty: Only flush... |
780 |
if (echoed && tty->ops->flush_chars) |
019ebdf9f n_tty: Eliminate ... |
781 |
tty->ops->flush_chars(tty); |
17bd79074 n_tty: Remove ech... |
782 |
} |
1075a6e2d n_tty: Fix appare... |
783 |
/* NB: echo_mark and echo_head should be equivalent here */ |
cbfd0340a n_tty: Process ec... |
784 785 786 |
static void flush_echoes(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; |
39434abd9 n_tty: Fix missin... |
787 788 |
if ((!L_ECHO(tty) && !L_ECHONL(tty)) || ldata->echo_commit == ldata->echo_head) |
cbfd0340a n_tty: Process ec... |
789 790 791 792 793 794 795 |
return; mutex_lock(&ldata->output_lock); ldata->echo_commit = ldata->echo_head; __process_echoes(tty); mutex_unlock(&ldata->output_lock); } |
a88a69c91 n_tty: Fix loss o... |
796 797 798 |
/** * add_echo_byte - add a byte to the echo buffer * @c: unicode byte to echo |
57c941212 TTY: n_tty, propa... |
799 |
* @ldata: n_tty data |
a88a69c91 n_tty: Fix loss o... |
800 801 |
* * Add a character or operation byte to the echo buffer. |
a88a69c91 n_tty: Fix loss o... |
802 |
*/ |
cbfd0340a n_tty: Process ec... |
803 |
static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata) |
a88a69c91 n_tty: Fix loss o... |
804 |
{ |
ebec3f8f5 n_tty: Access ech... |
805 806 807 |
*echo_buf_addr(ldata, ldata->echo_head) = c; smp_wmb(); /* Matches smp_rmb() in echo_buf(). */ ldata->echo_head++; |
a88a69c91 n_tty: Fix loss o... |
808 809 810 811 |
} /** * echo_move_back_col - add operation to move back a column |
57c941212 TTY: n_tty, propa... |
812 |
* @ldata: n_tty data |
a88a69c91 n_tty: Fix loss o... |
813 814 |
* * Add an operation to the echo buffer to move back one column. |
a88a69c91 n_tty: Fix loss o... |
815 |
*/ |
57c941212 TTY: n_tty, propa... |
816 |
static void echo_move_back_col(struct n_tty_data *ldata) |
a88a69c91 n_tty: Fix loss o... |
817 |
{ |
57c941212 TTY: n_tty, propa... |
818 819 |
add_echo_byte(ECHO_OP_START, ldata); add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata); |
a88a69c91 n_tty: Fix loss o... |
820 821 822 823 |
} /** * echo_set_canon_col - add operation to set the canon column |
57c941212 TTY: n_tty, propa... |
824 |
* @ldata: n_tty data |
a88a69c91 n_tty: Fix loss o... |
825 826 827 |
* * Add an operation to the echo buffer to set the canon column * to the current column. |
a88a69c91 n_tty: Fix loss o... |
828 |
*/ |
57c941212 TTY: n_tty, propa... |
829 |
static void echo_set_canon_col(struct n_tty_data *ldata) |
a88a69c91 n_tty: Fix loss o... |
830 |
{ |
57c941212 TTY: n_tty, propa... |
831 832 |
add_echo_byte(ECHO_OP_START, ldata); add_echo_byte(ECHO_OP_SET_CANON_COL, ldata); |
a88a69c91 n_tty: Fix loss o... |
833 834 835 836 837 838 |
} /** * echo_erase_tab - add operation to erase a tab * @num_chars: number of character columns already used * @after_tab: true if num_chars starts after a previous tab |
57c941212 TTY: n_tty, propa... |
839 |
* @ldata: n_tty data |
a88a69c91 n_tty: Fix loss o... |
840 841 842 843 844 845 846 847 |
* * Add an operation to the echo buffer to erase a tab. * * Called by the eraser function, which knows how many character * columns have been used since either a previous tab or the start * of input. This information will be used later, along with * canon column (if applicable), to go back the correct number * of columns. |
a88a69c91 n_tty: Fix loss o... |
848 849 850 |
*/ static void echo_erase_tab(unsigned int num_chars, int after_tab, |
57c941212 TTY: n_tty, propa... |
851 |
struct n_tty_data *ldata) |
a88a69c91 n_tty: Fix loss o... |
852 |
{ |
57c941212 TTY: n_tty, propa... |
853 854 |
add_echo_byte(ECHO_OP_START, ldata); add_echo_byte(ECHO_OP_ERASE_TAB, ldata); |
a88a69c91 n_tty: Fix loss o... |
855 856 857 858 859 860 861 |
/* We only need to know this modulo 8 (tab spacing) */ num_chars &= 7; /* Set the high bit as a flag if num_chars is after a previous tab */ if (after_tab) num_chars |= 0x80; |
300a6204b n_tty: clean up c... |
862 |
|
57c941212 TTY: n_tty, propa... |
863 |
add_echo_byte(num_chars, ldata); |
a88a69c91 n_tty: Fix loss o... |
864 865 866 867 868 869 870 871 872 873 874 |
} /** * echo_char_raw - echo a character raw * @c: unicode byte to echo * @tty: terminal device * * Echo user input back onto the screen. This must be called only when * L_ECHO(tty) is true. Called from the driver receive_buf path. * * This variant does not treat control characters specially. |
a88a69c91 n_tty: Fix loss o... |
875 |
*/ |
57c941212 TTY: n_tty, propa... |
876 |
static void echo_char_raw(unsigned char c, struct n_tty_data *ldata) |
a88a69c91 n_tty: Fix loss o... |
877 |
{ |
a88a69c91 n_tty: Fix loss o... |
878 |
if (c == ECHO_OP_START) { |
57c941212 TTY: n_tty, propa... |
879 880 |
add_echo_byte(ECHO_OP_START, ldata); add_echo_byte(ECHO_OP_START, ldata); |
a88a69c91 n_tty: Fix loss o... |
881 |
} else { |
57c941212 TTY: n_tty, propa... |
882 |
add_echo_byte(c, ldata); |
a88a69c91 n_tty: Fix loss o... |
883 |
} |
a88a69c91 n_tty: Fix loss o... |
884 |
} |
1da177e4c Linux-2.6.12-rc2 |
885 886 |
/** |
a88a69c91 n_tty: Fix loss o... |
887 |
* echo_char - echo a character |
1da177e4c Linux-2.6.12-rc2 |
888 889 890 |
* @c: unicode byte to echo * @tty: terminal device * |
4edf1827e n_tty: clean up o... |
891 |
* Echo user input back onto the screen. This must be called only when |
1da177e4c Linux-2.6.12-rc2 |
892 |
* L_ECHO(tty) is true. Called from the driver receive_buf path. |
17b820606 tty: Minor tidyup... |
893 |
* |
62b263585 n_tty: move echoc... |
894 895 |
* This variant tags control characters to be echoed as "^X" * (where X is the letter representing the control char). |
1da177e4c Linux-2.6.12-rc2 |
896 897 898 899 |
*/ static void echo_char(unsigned char c, struct tty_struct *tty) { |
bddc7152f TTY: move ldisc d... |
900 |
struct n_tty_data *ldata = tty->disc_data; |
a88a69c91 n_tty: Fix loss o... |
901 |
if (c == ECHO_OP_START) { |
57c941212 TTY: n_tty, propa... |
902 903 |
add_echo_byte(ECHO_OP_START, ldata); add_echo_byte(ECHO_OP_START, ldata); |
a88a69c91 n_tty: Fix loss o... |
904 |
} else { |
62b263585 n_tty: move echoc... |
905 |
if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') |
57c941212 TTY: n_tty, propa... |
906 907 |
add_echo_byte(ECHO_OP_START, ldata); add_echo_byte(c, ldata); |
a88a69c91 n_tty: Fix loss o... |
908 |
} |
1da177e4c Linux-2.6.12-rc2 |
909 |
} |
17b820606 tty: Minor tidyup... |
910 |
/** |
a88a69c91 n_tty: Fix loss o... |
911 |
* finish_erasing - complete erase |
57c941212 TTY: n_tty, propa... |
912 |
* @ldata: n_tty data |
17b820606 tty: Minor tidyup... |
913 |
*/ |
a88a69c91 n_tty: Fix loss o... |
914 |
|
57c941212 TTY: n_tty, propa... |
915 |
static inline void finish_erasing(struct n_tty_data *ldata) |
1da177e4c Linux-2.6.12-rc2 |
916 |
{ |
53c5ee2cf TTY: move ldisc d... |
917 |
if (ldata->erasing) { |
57c941212 TTY: n_tty, propa... |
918 |
echo_char_raw('/', ldata); |
53c5ee2cf TTY: move ldisc d... |
919 |
ldata->erasing = 0; |
1da177e4c Linux-2.6.12-rc2 |
920 921 922 923 924 925 926 927 |
} } /** * eraser - handle erase function * @c: character input * @tty: terminal device * |
3a4fa0a25 Fix misspellings ... |
928 |
* Perform erase and necessary output when an erase character is |
1da177e4c Linux-2.6.12-rc2 |
929 930 |
* present in the stream from the driver layer. Handles the complexities * of UTF-8 multibyte symbols. |
17b820606 tty: Minor tidyup... |
931 |
* |
6d76bd261 n_tty: Make N_TTY... |
932 933 |
* n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem |
1da177e4c Linux-2.6.12-rc2 |
934 |
*/ |
4edf1827e n_tty: clean up o... |
935 |
|
1da177e4c Linux-2.6.12-rc2 |
936 937 |
static void eraser(unsigned char c, struct tty_struct *tty) { |
53c5ee2cf TTY: move ldisc d... |
938 |
struct n_tty_data *ldata = tty->disc_data; |
1da177e4c Linux-2.6.12-rc2 |
939 |
enum { ERASE, WERASE, KILL } kill_type; |
bc5a5e3f4 n_tty: Don't wrap... |
940 941 942 |
size_t head; size_t cnt; int seen_alnums; |
1da177e4c Linux-2.6.12-rc2 |
943 |
|
ba2e68ac6 TTY: move ldisc d... |
944 |
if (ldata->read_head == ldata->canon_head) { |
7e94b1d9b n_tty: Output bel... |
945 |
/* process_output('\a', tty); */ /* what do you think? */ |
1da177e4c Linux-2.6.12-rc2 |
946 947 948 949 950 951 952 953 |
return; } if (c == ERASE_CHAR(tty)) kill_type = ERASE; else if (c == WERASE_CHAR(tty)) kill_type = WERASE; else { if (!L_ECHO(tty)) { |
ba2e68ac6 TTY: move ldisc d... |
954 |
ldata->read_head = ldata->canon_head; |
1da177e4c Linux-2.6.12-rc2 |
955 956 957 |
return; } if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { |
ba2e68ac6 TTY: move ldisc d... |
958 |
ldata->read_head = ldata->canon_head; |
57c941212 TTY: n_tty, propa... |
959 |
finish_erasing(ldata); |
1da177e4c Linux-2.6.12-rc2 |
960 961 962 |
echo_char(KILL_CHAR(tty), tty); /* Add a newline if ECHOK is on and ECHOKE is off. */ if (L_ECHOK(tty)) |
57c941212 TTY: n_tty, propa... |
963 964 |
echo_char_raw(' ', ldata); |
1da177e4c Linux-2.6.12-rc2 |
965 966 967 968 969 970 |
return; } kill_type = KILL; } seen_alnums = 0; |
3d63b7e4a n_tty: Fix stall ... |
971 |
while (MASK(ldata->read_head) != MASK(ldata->canon_head)) { |
ba2e68ac6 TTY: move ldisc d... |
972 |
head = ldata->read_head; |
1da177e4c Linux-2.6.12-rc2 |
973 974 975 |
/* erase a single possibly multibyte character */ do { |
bc5a5e3f4 n_tty: Don't wrap... |
976 977 |
head--; c = read_buf(ldata, head); |
3d63b7e4a n_tty: Fix stall ... |
978 979 |
} while (is_continuation(c, tty) && MASK(head) != MASK(ldata->canon_head)); |
1da177e4c Linux-2.6.12-rc2 |
980 981 982 983 984 985 986 987 988 989 990 991 |
/* do not partially erase */ if (is_continuation(c, tty)) break; if (kill_type == WERASE) { /* Equivalent to BSD's ALTWERASE. */ if (isalnum(c) || c == '_') seen_alnums++; else if (seen_alnums) break; } |
bc5a5e3f4 n_tty: Don't wrap... |
992 |
cnt = ldata->read_head - head; |
ba2e68ac6 TTY: move ldisc d... |
993 |
ldata->read_head = head; |
1da177e4c Linux-2.6.12-rc2 |
994 995 |
if (L_ECHO(tty)) { if (L_ECHOPRT(tty)) { |
53c5ee2cf TTY: move ldisc d... |
996 |
if (!ldata->erasing) { |
57c941212 TTY: n_tty, propa... |
997 |
echo_char_raw('\\', ldata); |
53c5ee2cf TTY: move ldisc d... |
998 |
ldata->erasing = 1; |
1da177e4c Linux-2.6.12-rc2 |
999 1000 1001 1002 |
} /* if cnt > 1, output a multi-byte character */ echo_char(c, tty); while (--cnt > 0) { |
bc5a5e3f4 n_tty: Don't wrap... |
1003 1004 |
head++; echo_char_raw(read_buf(ldata, head), ldata); |
57c941212 TTY: n_tty, propa... |
1005 |
echo_move_back_col(ldata); |
1da177e4c Linux-2.6.12-rc2 |
1006 1007 1008 1009 |
} } else if (kill_type == ERASE && !L_ECHOE(tty)) { echo_char(ERASE_CHAR(tty), tty); } else if (c == '\t') { |
a88a69c91 n_tty: Fix loss o... |
1010 1011 |
unsigned int num_chars = 0; int after_tab = 0; |
bc5a5e3f4 n_tty: Don't wrap... |
1012 |
size_t tail = ldata->read_head; |
a88a69c91 n_tty: Fix loss o... |
1013 1014 1015 1016 1017 1018 1019 1020 |
/* * Count the columns used for characters * since the start of input or after a * previous tab. * This info is used to go back the correct * number of columns. */ |
3d63b7e4a n_tty: Fix stall ... |
1021 |
while (MASK(tail) != MASK(ldata->canon_head)) { |
bc5a5e3f4 n_tty: Don't wrap... |
1022 1023 |
tail--; c = read_buf(ldata, tail); |
a88a69c91 n_tty: Fix loss o... |
1024 1025 1026 |
if (c == '\t') { after_tab = 1; break; |
300a6204b n_tty: clean up c... |
1027 |
} else if (iscntrl(c)) { |
1da177e4c Linux-2.6.12-rc2 |
1028 |
if (L_ECHOCTL(tty)) |
a88a69c91 n_tty: Fix loss o... |
1029 1030 1031 1032 |
num_chars += 2; } else if (!is_continuation(c, tty)) { num_chars++; } |
1da177e4c Linux-2.6.12-rc2 |
1033 |
} |
57c941212 TTY: n_tty, propa... |
1034 |
echo_erase_tab(num_chars, after_tab, ldata); |
1da177e4c Linux-2.6.12-rc2 |
1035 1036 |
} else { if (iscntrl(c) && L_ECHOCTL(tty)) { |
57c941212 TTY: n_tty, propa... |
1037 1038 1039 |
echo_char_raw('\b', ldata); echo_char_raw(' ', ldata); echo_char_raw('\b', ldata); |
1da177e4c Linux-2.6.12-rc2 |
1040 1041 |
} if (!iscntrl(c) || L_ECHOCTL(tty)) { |
57c941212 TTY: n_tty, propa... |
1042 1043 1044 |
echo_char_raw('\b', ldata); echo_char_raw(' ', ldata); echo_char_raw('\b', ldata); |
1da177e4c Linux-2.6.12-rc2 |
1045 1046 1047 1048 1049 1050 |
} } } if (kill_type == ERASE) break; } |
ba2e68ac6 TTY: move ldisc d... |
1051 |
if (ldata->read_head == ldata->canon_head && L_ECHO(tty)) |
57c941212 TTY: n_tty, propa... |
1052 |
finish_erasing(ldata); |
1da177e4c Linux-2.6.12-rc2 |
1053 1054 1055 1056 1057 1058 |
} /** * isig - handle the ISIG optio * @sig: signal * @tty: terminal |
1da177e4c Linux-2.6.12-rc2 |
1059 |
* |
8c985d18b n_tty: Fix unsafe... |
1060 1061 |
* Called when a signal is being sent due to terminal input. * Called from the driver receive_buf path so serialized. |
17b820606 tty: Minor tidyup... |
1062 |
* |
d2b6f4477 n_tty: Fix signal... |
1063 1064 1065 1066 |
* Performs input and output flush if !NOFLSH. In this context, the echo * buffer is 'output'. The signal is processed first to alert any current * readers or writers to discontinue and exit their i/o loops. * |
8c985d18b n_tty: Fix unsafe... |
1067 |
* Locking: ctrl_lock |
1da177e4c Linux-2.6.12-rc2 |
1068 |
*/ |
4edf1827e n_tty: clean up o... |
1069 |
|
3b19e0322 n_tty: signal and... |
1070 |
static void __isig(int sig, struct tty_struct *tty) |
1da177e4c Linux-2.6.12-rc2 |
1071 |
{ |
8c985d18b n_tty: Fix unsafe... |
1072 1073 1074 1075 |
struct pid *tty_pgrp = tty_get_pgrp(tty); if (tty_pgrp) { kill_pgrp(tty_pgrp, sig, 1); put_pid(tty_pgrp); |
1da177e4c Linux-2.6.12-rc2 |
1076 |
} |
3b19e0322 n_tty: signal and... |
1077 |
} |
d2b6f4477 n_tty: Fix signal... |
1078 |
|
3b19e0322 n_tty: signal and... |
1079 1080 1081 1082 1083 1084 1085 1086 1087 |
static void isig(int sig, struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; if (L_NOFLSH(tty)) { /* signal only */ __isig(sig, tty); } else { /* signal and flush */ |
d2b6f4477 n_tty: Fix signal... |
1088 1089 |
up_read(&tty->termios_rwsem); down_write(&tty->termios_rwsem); |
3b19e0322 n_tty: signal and... |
1090 |
__isig(sig, tty); |
d2b6f4477 n_tty: Fix signal... |
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 |
/* clear echo buffer */ mutex_lock(&ldata->output_lock); ldata->echo_head = ldata->echo_tail = 0; ldata->echo_mark = ldata->echo_commit = 0; mutex_unlock(&ldata->output_lock); /* clear output buffer */ tty_driver_flush_buffer(tty); /* clear input buffer */ reset_buffer_flags(tty->disc_data); /* notify pty master of flush */ if (tty->link) n_tty_packet_mode_flush(tty); up_write(&tty->termios_rwsem); down_read(&tty->termios_rwsem); } |
1da177e4c Linux-2.6.12-rc2 |
1110 1111 1112 1113 1114 1115 1116 1117 1118 |
} /** * n_tty_receive_break - handle break * @tty: terminal * * An RS232 break event has been hit in the incoming bitstream. This * can cause a variety of events depending upon the termios settings. * |
6d76bd261 n_tty: Make N_TTY... |
1119 1120 |
* n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem |
6d76bd261 n_tty: Make N_TTY... |
1121 1122 |
* * Note: may get exclusive termios_rwsem if flushing input buffer |
1da177e4c Linux-2.6.12-rc2 |
1123 |
*/ |
4edf1827e n_tty: clean up o... |
1124 |
|
4b293492a n_tty: Un-inline ... |
1125 |
static void n_tty_receive_break(struct tty_struct *tty) |
1da177e4c Linux-2.6.12-rc2 |
1126 |
{ |
57c941212 TTY: n_tty, propa... |
1127 |
struct n_tty_data *ldata = tty->disc_data; |
1da177e4c Linux-2.6.12-rc2 |
1128 1129 1130 |
if (I_IGNBRK(tty)) return; if (I_BRKINT(tty)) { |
8c985d18b n_tty: Fix unsafe... |
1131 |
isig(SIGINT, tty); |
1da177e4c Linux-2.6.12-rc2 |
1132 1133 1134 |
return; } if (I_PARMRK(tty)) { |
57c941212 TTY: n_tty, propa... |
1135 1136 |
put_tty_queue('\377', ldata); put_tty_queue('\0', ldata); |
1da177e4c Linux-2.6.12-rc2 |
1137 |
} |
57c941212 TTY: n_tty, propa... |
1138 |
put_tty_queue('\0', ldata); |
1da177e4c Linux-2.6.12-rc2 |
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 |
} /** * n_tty_receive_overrun - handle overrun reporting * @tty: terminal * * Data arrived faster than we could process it. While the tty * driver has flagged this the bits that were missed are gone * forever. * * Called from the receive_buf path so single threaded. Does not * need locking as num_overrun and overrun_time are function * private. */ |
4edf1827e n_tty: clean up o... |
1153 |
|
4b293492a n_tty: Un-inline ... |
1154 |
static void n_tty_receive_overrun(struct tty_struct *tty) |
1da177e4c Linux-2.6.12-rc2 |
1155 |
{ |
53c5ee2cf TTY: move ldisc d... |
1156 |
struct n_tty_data *ldata = tty->disc_data; |
1da177e4c Linux-2.6.12-rc2 |
1157 |
|
53c5ee2cf TTY: move ldisc d... |
1158 1159 1160 |
ldata->num_overrun++; if (time_after(jiffies, ldata->overrun_time + HZ) || time_after(ldata->overrun_time, jiffies)) { |
339f36ba1 tty: Define tty_*... |
1161 1162 |
tty_warn(tty, "%d input overrun(s) ", ldata->num_overrun); |
53c5ee2cf TTY: move ldisc d... |
1163 1164 |
ldata->overrun_time = jiffies; ldata->num_overrun = 0; |
1da177e4c Linux-2.6.12-rc2 |
1165 1166 1167 1168 1169 1170 1171 1172 1173 |
} } /** * n_tty_receive_parity_error - error notifier * @tty: terminal device * @c: character * * Process a parity error and queue the right data to indicate |
6d76bd261 n_tty: Make N_TTY... |
1174 1175 1176 1177 |
* the error case if necessary. * * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem |
1da177e4c Linux-2.6.12-rc2 |
1178 |
*/ |
4b293492a n_tty: Un-inline ... |
1179 |
static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) |
1da177e4c Linux-2.6.12-rc2 |
1180 |
{ |
57c941212 TTY: n_tty, propa... |
1181 |
struct n_tty_data *ldata = tty->disc_data; |
66528f906 tty: Correct INPC... |
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 |
if (I_INPCK(tty)) { if (I_IGNPAR(tty)) return; if (I_PARMRK(tty)) { put_tty_queue('\377', ldata); put_tty_queue('\0', ldata); put_tty_queue(c, ldata); } else put_tty_queue('\0', ldata); } else |
57c941212 TTY: n_tty, propa... |
1192 |
put_tty_queue(c, ldata); |
1da177e4c Linux-2.6.12-rc2 |
1193 |
} |
b0ac50be1 n_tty: Factor sig... |
1194 1195 1196 |
static void n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) { |
d2b6f4477 n_tty: Fix signal... |
1197 |
isig(signal, tty); |
b0ac50be1 n_tty: Factor sig... |
1198 1199 1200 1201 1202 |
if (I_IXON(tty)) start_tty(tty); if (L_ECHO(tty)) { echo_char(c, tty); commit_echoes(tty); |
e2613be50 n_tty: Fix stale ... |
1203 1204 |
} else process_echoes(tty); |
b0ac50be1 n_tty: Factor sig... |
1205 1206 |
return; } |
1da177e4c Linux-2.6.12-rc2 |
1207 1208 1209 1210 1211 1212 |
/** * n_tty_receive_char - perform processing * @tty: terminal device * @c: character * * Process an individual character of input received from the driver. |
4edf1827e n_tty: clean up o... |
1213 |
* This is serialized with respect to itself by the rules for the |
1da177e4c Linux-2.6.12-rc2 |
1214 |
* driver above. |
6d76bd261 n_tty: Make N_TTY... |
1215 1216 1217 1218 |
* * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * publishes canon_head if canonical mode is active |
e60d27c4d n_tty: Factor LNE... |
1219 1220 |
* * Returns 1 if LNEXT was received, else returns 0 |
1da177e4c Linux-2.6.12-rc2 |
1221 |
*/ |
e60d27c4d n_tty: Factor LNE... |
1222 |
static int |
4b1f79c2d n_tty: Split n_tt... |
1223 |
n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) |
1da177e4c Linux-2.6.12-rc2 |
1224 |
{ |
53c5ee2cf TTY: move ldisc d... |
1225 |
struct n_tty_data *ldata = tty->disc_data; |
1da177e4c Linux-2.6.12-rc2 |
1226 |
|
1da177e4c Linux-2.6.12-rc2 |
1227 1228 1229 |
if (I_IXON(tty)) { if (c == START_CHAR(tty)) { start_tty(tty); |
e2613be50 n_tty: Fix stale ... |
1230 |
process_echoes(tty); |
e60d27c4d n_tty: Factor LNE... |
1231 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1232 1233 1234 |
} if (c == STOP_CHAR(tty)) { stop_tty(tty); |
e60d27c4d n_tty: Factor LNE... |
1235 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1236 1237 |
} } |
575537b32 Resume TTY on SUS... |
1238 |
|
1da177e4c Linux-2.6.12-rc2 |
1239 |
if (L_ISIG(tty)) { |
b0ac50be1 n_tty: Factor sig... |
1240 1241 |
if (c == INTR_CHAR(tty)) { n_tty_receive_signal_char(tty, SIGINT, c); |
e60d27c4d n_tty: Factor LNE... |
1242 |
return 0; |
b0ac50be1 n_tty: Factor sig... |
1243 1244 |
} else if (c == QUIT_CHAR(tty)) { n_tty_receive_signal_char(tty, SIGQUIT, c); |
e60d27c4d n_tty: Factor LNE... |
1245 |
return 0; |
b0ac50be1 n_tty: Factor sig... |
1246 1247 |
} else if (c == SUSP_CHAR(tty)) { n_tty_receive_signal_char(tty, SIGTSTP, c); |
e60d27c4d n_tty: Factor LNE... |
1248 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1249 1250 |
} } |
575537b32 Resume TTY on SUS... |
1251 |
|
855df3c08 n_tty: Eliminate ... |
1252 1253 1254 1255 |
if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) { start_tty(tty); process_echoes(tty); } |
575537b32 Resume TTY on SUS... |
1256 1257 |
if (c == '\r') { if (I_IGNCR(tty)) |
e60d27c4d n_tty: Factor LNE... |
1258 |
return 0; |
575537b32 Resume TTY on SUS... |
1259 1260 1261 1262 1263 1264 |
if (I_ICRNL(tty)) c = ' '; } else if (c == ' ' && I_INLCR(tty)) c = '\r'; |
53c5ee2cf TTY: move ldisc d... |
1265 |
if (ldata->icanon) { |
1da177e4c Linux-2.6.12-rc2 |
1266 1267 1268 |
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { eraser(c, tty); |
17bd79074 n_tty: Remove ech... |
1269 |
commit_echoes(tty); |
e60d27c4d n_tty: Factor LNE... |
1270 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1271 1272 |
} if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { |
53c5ee2cf TTY: move ldisc d... |
1273 |
ldata->lnext = 1; |
1da177e4c Linux-2.6.12-rc2 |
1274 |
if (L_ECHO(tty)) { |
57c941212 TTY: n_tty, propa... |
1275 |
finish_erasing(ldata); |
1da177e4c Linux-2.6.12-rc2 |
1276 |
if (L_ECHOCTL(tty)) { |
57c941212 TTY: n_tty, propa... |
1277 1278 |
echo_char_raw('^', ldata); echo_char_raw('\b', ldata); |
17bd79074 n_tty: Remove ech... |
1279 |
commit_echoes(tty); |
1da177e4c Linux-2.6.12-rc2 |
1280 1281 |
} } |
e60d27c4d n_tty: Factor LNE... |
1282 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
1283 |
} |
e60d27c4d n_tty: Factor LNE... |
1284 |
if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) { |
bc5a5e3f4 n_tty: Don't wrap... |
1285 |
size_t tail = ldata->canon_head; |
1da177e4c Linux-2.6.12-rc2 |
1286 |
|
57c941212 TTY: n_tty, propa... |
1287 |
finish_erasing(ldata); |
1da177e4c Linux-2.6.12-rc2 |
1288 |
echo_char(c, tty); |
57c941212 TTY: n_tty, propa... |
1289 1290 |
echo_char_raw(' ', ldata); |
3d63b7e4a n_tty: Fix stall ... |
1291 |
while (MASK(tail) != MASK(ldata->read_head)) { |
bc5a5e3f4 n_tty: Don't wrap... |
1292 1293 |
echo_char(read_buf(ldata, tail), tty); tail++; |
1da177e4c Linux-2.6.12-rc2 |
1294 |
} |
17bd79074 n_tty: Remove ech... |
1295 |
commit_echoes(tty); |
e60d27c4d n_tty: Factor LNE... |
1296 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1297 1298 1299 |
} if (c == ' ') { |
acc71bbad n_tty: Fix hanfli... |
1300 |
if (L_ECHO(tty) || L_ECHONL(tty)) { |
57c941212 TTY: n_tty, propa... |
1301 1302 |
echo_char_raw(' ', ldata); |
17bd79074 n_tty: Remove ech... |
1303 |
commit_echoes(tty); |
1da177e4c Linux-2.6.12-rc2 |
1304 1305 1306 1307 |
} goto handle_newline; } if (c == EOF_CHAR(tty)) { |
1da177e4c Linux-2.6.12-rc2 |
1308 1309 1310 1311 1312 1313 1314 1315 1316 |
c = __DISABLED_CHAR; goto handle_newline; } if ((c == EOL_CHAR(tty)) || (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) { /* * XXX are EOL_CHAR and EOL2_CHAR echoed?!? */ if (L_ECHO(tty)) { |
1da177e4c Linux-2.6.12-rc2 |
1317 |
/* Record the column of first canon char. */ |
ba2e68ac6 TTY: move ldisc d... |
1318 |
if (ldata->canon_head == ldata->read_head) |
57c941212 TTY: n_tty, propa... |
1319 |
echo_set_canon_col(ldata); |
1da177e4c Linux-2.6.12-rc2 |
1320 |
echo_char(c, tty); |
17bd79074 n_tty: Remove ech... |
1321 |
commit_echoes(tty); |
1da177e4c Linux-2.6.12-rc2 |
1322 1323 1324 1325 1326 |
} /* * XXX does PARMRK doubling happen for * EOL_CHAR and EOL2_CHAR? */ |
001ba9237 n_tty: Refactor P... |
1327 |
if (c == (unsigned char) '\377' && I_PARMRK(tty)) |
57c941212 TTY: n_tty, propa... |
1328 |
put_tty_queue(c, ldata); |
1da177e4c Linux-2.6.12-rc2 |
1329 |
|
4edf1827e n_tty: clean up o... |
1330 |
handle_newline: |
bc5a5e3f4 n_tty: Don't wrap... |
1331 |
set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags); |
6d76bd261 n_tty: Make N_TTY... |
1332 |
put_tty_queue(c, ldata); |
70aca71f9 n_tty: Fix unorde... |
1333 |
smp_store_release(&ldata->canon_head, ldata->read_head); |
1da177e4c Linux-2.6.12-rc2 |
1334 |
kill_fasync(&tty->fasync, SIGIO, POLL_IN); |
a9a08845e vfs: do bulk POLL... |
1335 |
wake_up_interruptible_poll(&tty->read_wait, EPOLLIN); |
e60d27c4d n_tty: Factor LNE... |
1336 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1337 1338 |
} } |
4edf1827e n_tty: clean up o... |
1339 |
|
acc71bbad n_tty: Fix hanfli... |
1340 |
if (L_ECHO(tty)) { |
57c941212 TTY: n_tty, propa... |
1341 |
finish_erasing(ldata); |
1da177e4c Linux-2.6.12-rc2 |
1342 1343 |
if (c == ' ') |
57c941212 TTY: n_tty, propa... |
1344 1345 |
echo_char_raw(' ', ldata); |
1da177e4c Linux-2.6.12-rc2 |
1346 1347 |
else { /* Record the column of first canon char. */ |
ba2e68ac6 TTY: move ldisc d... |
1348 |
if (ldata->canon_head == ldata->read_head) |
57c941212 TTY: n_tty, propa... |
1349 |
echo_set_canon_col(ldata); |
1da177e4c Linux-2.6.12-rc2 |
1350 1351 |
echo_char(c, tty); } |
17bd79074 n_tty: Remove ech... |
1352 |
commit_echoes(tty); |
1da177e4c Linux-2.6.12-rc2 |
1353 |
} |
001ba9237 n_tty: Refactor P... |
1354 1355 |
/* PARMRK doubling check */ if (c == (unsigned char) '\377' && I_PARMRK(tty)) |
57c941212 TTY: n_tty, propa... |
1356 |
put_tty_queue(c, ldata); |
1da177e4c Linux-2.6.12-rc2 |
1357 |
|
57c941212 TTY: n_tty, propa... |
1358 |
put_tty_queue(c, ldata); |
e60d27c4d n_tty: Factor LNE... |
1359 |
return 0; |
4edf1827e n_tty: clean up o... |
1360 |
} |
1da177e4c Linux-2.6.12-rc2 |
1361 |
|
e60d27c4d n_tty: Factor LNE... |
1362 1363 |
static inline void n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c) |
4b1f79c2d n_tty: Split n_tt... |
1364 1365 |
{ struct n_tty_data *ldata = tty->disc_data; |
4b1f79c2d n_tty: Split n_tt... |
1366 |
|
e60d27c4d n_tty: Factor LNE... |
1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 |
if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) { start_tty(tty); process_echoes(tty); } if (L_ECHO(tty)) { finish_erasing(ldata); /* Record the column of first canon char. */ if (ldata->canon_head == ldata->read_head) echo_set_canon_col(ldata); echo_char(c, tty); commit_echoes(tty); |
4b1f79c2d n_tty: Split n_tt... |
1378 |
} |
001ba9237 n_tty: Refactor P... |
1379 1380 |
/* PARMRK doubling check */ if (c == (unsigned char) '\377' && I_PARMRK(tty)) |
e60d27c4d n_tty: Factor LNE... |
1381 1382 1383 |
put_tty_queue(c, ldata); put_tty_queue(c, ldata); } |
4b1f79c2d n_tty: Split n_tt... |
1384 |
|
eb3e4668b n_tty: Un-inline ... |
1385 |
static void n_tty_receive_char(struct tty_struct *tty, unsigned char c) |
e60d27c4d n_tty: Factor LNE... |
1386 1387 |
{ n_tty_receive_char_inline(tty, c); |
4b1f79c2d n_tty: Split n_tt... |
1388 |
} |
ad0cc7baf n_tty: Factor tty... |
1389 |
static inline void |
7de971b05 n_tty: Factor PAR... |
1390 1391 1392 |
n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c) { struct n_tty_data *ldata = tty->disc_data; |
e60d27c4d n_tty: Factor LNE... |
1393 1394 1395 |
if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) { start_tty(tty); process_echoes(tty); |
7de971b05 n_tty: Factor PAR... |
1396 |
} |
e60d27c4d n_tty: Factor LNE... |
1397 1398 1399 1400 1401 1402 1403 1404 1405 |
if (L_ECHO(tty)) { finish_erasing(ldata); /* Record the column of first canon char. */ if (ldata->canon_head == ldata->read_head) echo_set_canon_col(ldata); echo_char(c, tty); commit_echoes(tty); } put_tty_queue(c, ldata); |
7de971b05 n_tty: Factor PAR... |
1406 |
} |
8dc4b25d2 n_tty: Un-inline ... |
1407 |
static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) |
ad0cc7baf n_tty: Factor tty... |
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 |
{ if (I_ISTRIP(tty)) c &= 0x7f; if (I_IUCLC(tty) && L_IEXTEN(tty)) c = tolower(c); if (I_IXON(tty)) { if (c == STOP_CHAR(tty)) stop_tty(tty); else if (c == START_CHAR(tty) || (tty->stopped && !tty->flow_stopped && I_IXANY(tty) && c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty))) { start_tty(tty); process_echoes(tty); } } } |
d2f8d7abd n_tty: Factor fla... |
1426 1427 1428 |
static void n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag) { |
d2f8d7abd n_tty: Factor fla... |
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 |
switch (flag) { case TTY_BREAK: n_tty_receive_break(tty); break; case TTY_PARITY: case TTY_FRAME: n_tty_receive_parity_error(tty, c); break; case TTY_OVERRUN: n_tty_receive_overrun(tty); break; default: |
339f36ba1 tty: Define tty_*... |
1441 1442 |
tty_err(tty, "unknown flag %d ", flag); |
d2f8d7abd n_tty: Factor fla... |
1443 1444 1445 |
break; } } |
e60d27c4d n_tty: Factor LNE... |
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 |
static void n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag) { struct n_tty_data *ldata = tty->disc_data; ldata->lnext = 0; if (likely(flag == TTY_NORMAL)) { if (I_ISTRIP(tty)) c &= 0x7f; if (I_IUCLC(tty) && L_IEXTEN(tty)) c = tolower(c); n_tty_receive_char(tty, c); } else n_tty_receive_char_flagged(tty, c, flag); } |
4a23a4df5 n_tty: Factor 're... |
1461 1462 1463 1464 1465 1466 1467 1468 |
static void n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct n_tty_data *ldata = tty->disc_data; size_t n, head; head = ldata->read_head & (N_TTY_BUF_SIZE - 1); |
70aca71f9 n_tty: Fix unorde... |
1469 |
n = min_t(size_t, count, N_TTY_BUF_SIZE - head); |
4a23a4df5 n_tty: Factor 're... |
1470 1471 1472 1473 1474 1475 |
memcpy(read_buf_addr(ldata, head), cp, n); ldata->read_head += n; cp += n; count -= n; head = ldata->read_head & (N_TTY_BUF_SIZE - 1); |
70aca71f9 n_tty: Fix unorde... |
1476 |
n = min_t(size_t, count, N_TTY_BUF_SIZE - head); |
4a23a4df5 n_tty: Factor 're... |
1477 1478 1479 |
memcpy(read_buf_addr(ldata, head), cp, n); ldata->read_head += n; } |
554117bdc n_tty: Factor raw... |
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 |
static void n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct n_tty_data *ldata = tty->disc_data; char flag = TTY_NORMAL; while (count--) { if (fp) flag = *fp++; if (likely(flag == TTY_NORMAL)) put_tty_queue(*cp++, ldata); else n_tty_receive_char_flagged(tty, *cp++, flag); } } |
ad0cc7baf n_tty: Factor tty... |
1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 |
static void n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { char flag = TTY_NORMAL; while (count--) { if (fp) flag = *fp++; if (likely(flag == TTY_NORMAL)) n_tty_receive_char_closing(tty, *cp++); |
ad0cc7baf n_tty: Factor tty... |
1507 1508 |
} } |
7d88d637a n_tty: Factor sta... |
1509 1510 |
static void n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp, |
6baad0086 n_tty: Factor IST... |
1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 |
char *fp, int count) { struct n_tty_data *ldata = tty->disc_data; char flag = TTY_NORMAL; while (count--) { if (fp) flag = *fp++; if (likely(flag == TTY_NORMAL)) { unsigned char c = *cp++; if (I_ISTRIP(tty)) c &= 0x7f; if (I_IUCLC(tty) && L_IEXTEN(tty)) c = tolower(c); if (L_EXTPROC(tty)) { put_tty_queue(c, ldata); continue; } |
e60d27c4d n_tty: Factor LNE... |
1530 1531 1532 1533 1534 1535 1536 1537 |
if (!test_bit(c, ldata->char_map)) n_tty_receive_char_inline(tty, c); else if (n_tty_receive_char_special(tty, c) && count) { if (fp) flag = *fp++; n_tty_receive_char_lnext(tty, *cp++, flag); count--; } |
6baad0086 n_tty: Factor IST... |
1538 1539 1540 1541 1542 1543 1544 1545 |
} else n_tty_receive_char_flagged(tty, *cp++, flag); } } static void n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) |
7d88d637a n_tty: Factor sta... |
1546 |
{ |
e60d27c4d n_tty: Factor LNE... |
1547 |
struct n_tty_data *ldata = tty->disc_data; |
7d88d637a n_tty: Factor sta... |
1548 1549 1550 1551 1552 |
char flag = TTY_NORMAL; while (count--) { if (fp) flag = *fp++; |
e60d27c4d n_tty: Factor LNE... |
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 |
if (likely(flag == TTY_NORMAL)) { unsigned char c = *cp++; if (!test_bit(c, ldata->char_map)) n_tty_receive_char_fast(tty, c); else if (n_tty_receive_char_special(tty, c) && count) { if (fp) flag = *fp++; n_tty_receive_char_lnext(tty, *cp++, flag); count--; } } else |
7d88d637a n_tty: Factor sta... |
1565 1566 1567 |
n_tty_receive_char_flagged(tty, *cp++, flag); } } |
24a89d1cb tty: Make ldisc i... |
1568 1569 |
static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) |
1da177e4c Linux-2.6.12-rc2 |
1570 |
{ |
53c5ee2cf TTY: move ldisc d... |
1571 |
struct n_tty_data *ldata = tty->disc_data; |
a1dd30e9b n_tty: Special ca... |
1572 |
bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty)); |
1da177e4c Linux-2.6.12-rc2 |
1573 |
|
4a23a4df5 n_tty: Factor 're... |
1574 1575 |
if (ldata->real_raw) n_tty_receive_buf_real_raw(tty, cp, fp, count); |
a1dd30e9b n_tty: Special ca... |
1576 |
else if (ldata->raw || (L_EXTPROC(tty) && !preops)) |
554117bdc n_tty: Factor raw... |
1577 |
n_tty_receive_buf_raw(tty, cp, fp, count); |
ad0cc7baf n_tty: Factor tty... |
1578 1579 |
else if (tty->closing && !L_EXTPROC(tty)) n_tty_receive_buf_closing(tty, cp, fp, count); |
4a23a4df5 n_tty: Factor 're... |
1580 |
else { |
e60d27c4d n_tty: Factor LNE... |
1581 1582 1583 1584 1585 1586 1587 1588 |
if (ldata->lnext) { char flag = TTY_NORMAL; if (fp) flag = *fp++; n_tty_receive_char_lnext(tty, *cp++, flag); count--; } |
7de971b05 n_tty: Factor PAR... |
1589 |
if (!preops && !I_PARMRK(tty)) |
6baad0086 n_tty: Factor IST... |
1590 1591 1592 |
n_tty_receive_buf_fast(tty, cp, fp, count); else n_tty_receive_buf_standard(tty, cp, fp, count); |
cbfd0340a n_tty: Process ec... |
1593 1594 |
flush_echoes(tty); |
f34d7a5b7 tty: The big oper... |
1595 1596 |
if (tty->ops->flush_chars) tty->ops->flush_chars(tty); |
1da177e4c Linux-2.6.12-rc2 |
1597 |
} |
70aca71f9 n_tty: Fix unorde... |
1598 1599 1600 1601 1602 |
if (ldata->icanon && !L_EXTPROC(tty)) return; /* publish read_head to consumer */ smp_store_release(&ldata->commit_head, ldata->read_head); |
33d713633 n_tty: Always wak... |
1603 |
if (read_cnt(ldata)) { |
1da177e4c Linux-2.6.12-rc2 |
1604 |
kill_fasync(&tty->fasync, SIGIO, POLL_IN); |
a9a08845e vfs: do bulk POLL... |
1605 |
wake_up_interruptible_poll(&tty->read_wait, EPOLLIN); |
1da177e4c Linux-2.6.12-rc2 |
1606 |
} |
1da177e4c Linux-2.6.12-rc2 |
1607 |
} |
fb5ef9e7d n_tty: Fix read b... |
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 |
/** * n_tty_receive_buf_common - process input * @tty: device to receive input * @cp: input chars * @fp: flags for each char (if NULL, all chars are TTY_NORMAL) * @count: number of input chars in @cp * * Called by the terminal driver when a block of characters has * been received. This function must be called from soft contexts * not from interrupt context. The driver is responsible for making * calls one at a time and in order (or using flush_to_ldisc) * * Returns the # of input chars from @cp which were processed. * * In canonical mode, the maximum line length is 4096 chars (including * the line termination char); lines longer than 4096 chars are * truncated. After 4095 chars, input data is still processed but * not stored. Overflow processing ensures the tty can always * receive more input until at least one line can be read. * * In non-canonical mode, the read buffer will only accept 4095 chars; * this provides the necessary space for a newline char if the input * mode is switched to canonical. * * Note it is possible for the read buffer to _contain_ 4096 chars * in non-canonical mode: the read buffer could already contain the * maximum canon line of 4096 chars when the mode is switched to * non-canonical. * * n_tty_receive_buf()/producer path: * claims non-exclusive termios_rwsem * publishes commit_head or canon_head */ |
5c32d1237 n_tty: Merge .rec... |
1641 1642 1643 |
static int n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp, char *fp, int count, int flow) |
24a89d1cb tty: Make ldisc i... |
1644 1645 |
{ struct n_tty_data *ldata = tty->disc_data; |
fb5ef9e7d n_tty: Fix read b... |
1646 |
int room, n, rcvd = 0, overflow; |
24a89d1cb tty: Make ldisc i... |
1647 |
|
9356b535f n_tty: Access ter... |
1648 |
down_read(&tty->termios_rwsem); |
c96cf923a tty: Don't block ... |
1649 |
do { |
70aca71f9 n_tty: Fix unorde... |
1650 |
/* |
06c49f9fa n_tty: Fix PARMRK... |
1651 1652 |
* When PARMRK is set, each input char may take up to 3 chars * in the read buf; reduce the buffer space avail by 3x |
70aca71f9 n_tty: Fix unorde... |
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 |
* * If we are doing input canonicalization, and there are no * pending newlines, let characters through without limit, so * that erase characters will be handled. Other excess * characters will be beeped. * * paired with store in *_copy_from_read_buf() -- guarantees * the consumer has loaded the data in read_buf up to the new * read_tail (so this producer will not overwrite unread data) */ size_t tail = smp_load_acquire(&ldata->read_tail); |
70aca71f9 n_tty: Fix unorde... |
1664 |
|
fb5ef9e7d n_tty: Fix read b... |
1665 |
room = N_TTY_BUF_SIZE - (ldata->read_head - tail); |
70aca71f9 n_tty: Fix unorde... |
1666 |
if (I_PARMRK(tty)) |
fb5ef9e7d n_tty: Fix read b... |
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 |
room = (room + 2) / 3; room--; if (room <= 0) { overflow = ldata->icanon && ldata->canon_head == tail; if (overflow && room < 0) ldata->read_head--; room = overflow; ldata->no_room = flow && !room; } else overflow = 0; |
70aca71f9 n_tty: Fix unorde... |
1677 |
|
19e2ad6a0 n_tty: Remove ove... |
1678 |
n = min(count, room); |
fb5ef9e7d n_tty: Fix read b... |
1679 |
if (!n) |
19e2ad6a0 n_tty: Remove ove... |
1680 |
break; |
fb5ef9e7d n_tty: Fix read b... |
1681 1682 1683 1684 |
/* ignore parity errors if handling overflow */ if (!overflow || !fp || *fp != TTY_PARITY) __receive_buf(tty, cp, fp, n); |
19e2ad6a0 n_tty: Remove ove... |
1685 1686 1687 1688 1689 |
cp += n; if (fp) fp += n; count -= n; rcvd += n; |
c96cf923a tty: Don't block ... |
1690 |
} while (!test_bit(TTY_LDISC_CHANGING, &tty->flags)); |
24a89d1cb tty: Make ldisc i... |
1691 |
|
19e2ad6a0 n_tty: Remove ove... |
1692 |
tty->receive_room = room; |
fb5ef9e7d n_tty: Fix read b... |
1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 |
/* Unthrottle if handling overflow on pty */ if (tty->driver->type == TTY_DRIVER_TYPE_PTY) { if (overflow) { tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE); tty_unthrottle_safe(tty); __tty_set_flow_change(tty, 0); } } else n_tty_check_throttle(tty); |
9356b535f n_tty: Access ter... |
1703 |
up_read(&tty->termios_rwsem); |
19e2ad6a0 n_tty: Remove ove... |
1704 |
return rcvd; |
24a89d1cb tty: Make ldisc i... |
1705 |
} |
5c32d1237 n_tty: Merge .rec... |
1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 |
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { n_tty_receive_buf_common(tty, cp, fp, count, 0); } static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { return n_tty_receive_buf_common(tty, cp, fp, count, 1); } |
1da177e4c Linux-2.6.12-rc2 |
1717 1718 1719 1720 1721 1722 1723 |
/** * n_tty_set_termios - termios data changed * @tty: terminal * @old: previous data * * Called by the tty layer when the user changes termios flags so * that the line discipline can plan ahead. This function cannot sleep |
4edf1827e n_tty: clean up o... |
1724 |
* and is protected from re-entry by the tty layer. The user is |
1da177e4c Linux-2.6.12-rc2 |
1725 1726 |
* guaranteed that this function will not be re-entered or in progress * when the ldisc is closed. |
17b820606 tty: Minor tidyup... |
1727 |
* |
6a1c0680c tty: Convert term... |
1728 |
* Locking: Caller holds tty->termios_rwsem |
1da177e4c Linux-2.6.12-rc2 |
1729 |
*/ |
4edf1827e n_tty: clean up o... |
1730 1731 |
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) |
1da177e4c Linux-2.6.12-rc2 |
1732 |
{ |
53c5ee2cf TTY: move ldisc d... |
1733 |
struct n_tty_data *ldata = tty->disc_data; |
47afa7a5a tty: some ICANON ... |
1734 |
|
966031f34 n_tty: fix EXTPRO... |
1735 |
if (!old || (old->c_lflag ^ tty->termios.c_lflag) & (ICANON | EXTPROC)) { |
3fe780b37 TTY: move ldisc d... |
1736 |
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); |
4d0ed1827 n_tty: Fix buffer... |
1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 |
ldata->line_start = ldata->read_tail; if (!L_ICANON(tty) || !read_cnt(ldata)) { ldata->canon_head = ldata->read_tail; ldata->push = 0; } else { set_bit((ldata->read_head - 1) & (N_TTY_BUF_SIZE - 1), ldata->read_flags); ldata->canon_head = ldata->read_head; ldata->push = 1; } |
70aca71f9 n_tty: Fix unorde... |
1747 |
ldata->commit_head = ldata->read_head; |
53c5ee2cf TTY: move ldisc d... |
1748 |
ldata->erasing = 0; |
6f9b028a8 n_tty: Reset lnex... |
1749 |
ldata->lnext = 0; |
47afa7a5a tty: some ICANON ... |
1750 |
} |
53c5ee2cf TTY: move ldisc d... |
1751 |
ldata->icanon = (L_ICANON(tty) != 0); |
582f55907 tty: Remove TTY_H... |
1752 |
|
1da177e4c Linux-2.6.12-rc2 |
1753 1754 1755 1756 |
if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { |
1bb9d5628 n_tty: Rename pro... |
1757 |
bitmap_zero(ldata->char_map, 256); |
1da177e4c Linux-2.6.12-rc2 |
1758 1759 |
if (I_IGNCR(tty) || I_ICRNL(tty)) |
1bb9d5628 n_tty: Rename pro... |
1760 |
set_bit('\r', ldata->char_map); |
1da177e4c Linux-2.6.12-rc2 |
1761 |
if (I_INLCR(tty)) |
1bb9d5628 n_tty: Rename pro... |
1762 1763 |
set_bit(' ', ldata->char_map); |
1da177e4c Linux-2.6.12-rc2 |
1764 1765 |
if (L_ICANON(tty)) { |
1bb9d5628 n_tty: Rename pro... |
1766 1767 1768 1769 1770 1771 |
set_bit(ERASE_CHAR(tty), ldata->char_map); set_bit(KILL_CHAR(tty), ldata->char_map); set_bit(EOF_CHAR(tty), ldata->char_map); set_bit(' ', ldata->char_map); set_bit(EOL_CHAR(tty), ldata->char_map); |
1da177e4c Linux-2.6.12-rc2 |
1772 |
if (L_IEXTEN(tty)) { |
1bb9d5628 n_tty: Rename pro... |
1773 1774 1775 |
set_bit(WERASE_CHAR(tty), ldata->char_map); set_bit(LNEXT_CHAR(tty), ldata->char_map); set_bit(EOL2_CHAR(tty), ldata->char_map); |
1da177e4c Linux-2.6.12-rc2 |
1776 1777 |
if (L_ECHO(tty)) set_bit(REPRINT_CHAR(tty), |
1bb9d5628 n_tty: Rename pro... |
1778 |
ldata->char_map); |
1da177e4c Linux-2.6.12-rc2 |
1779 1780 1781 |
} } if (I_IXON(tty)) { |
1bb9d5628 n_tty: Rename pro... |
1782 1783 |
set_bit(START_CHAR(tty), ldata->char_map); set_bit(STOP_CHAR(tty), ldata->char_map); |
1da177e4c Linux-2.6.12-rc2 |
1784 1785 |
} if (L_ISIG(tty)) { |
1bb9d5628 n_tty: Rename pro... |
1786 1787 1788 |
set_bit(INTR_CHAR(tty), ldata->char_map); set_bit(QUIT_CHAR(tty), ldata->char_map); set_bit(SUSP_CHAR(tty), ldata->char_map); |
1da177e4c Linux-2.6.12-rc2 |
1789 |
} |
1bb9d5628 n_tty: Rename pro... |
1790 |
clear_bit(__DISABLED_CHAR, ldata->char_map); |
53c5ee2cf TTY: move ldisc d... |
1791 1792 |
ldata->raw = 0; ldata->real_raw = 0; |
1da177e4c Linux-2.6.12-rc2 |
1793 |
} else { |
53c5ee2cf TTY: move ldisc d... |
1794 |
ldata->raw = 1; |
1da177e4c Linux-2.6.12-rc2 |
1795 1796 1797 |
if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) && (I_IGNPAR(tty) || !I_INPCK(tty)) && (tty->driver->flags & TTY_DRIVER_REAL_RAW)) |
53c5ee2cf TTY: move ldisc d... |
1798 |
ldata->real_raw = 1; |
1da177e4c Linux-2.6.12-rc2 |
1799 |
else |
53c5ee2cf TTY: move ldisc d... |
1800 |
ldata->real_raw = 0; |
1da177e4c Linux-2.6.12-rc2 |
1801 |
} |
dab73b4eb TTY: Fix tty miss... |
1802 1803 1804 1805 |
/* * Fix tty hang when I_IXON(tty) is cleared, but the tty * been stopped by STOP_CHAR(tty) before it. */ |
e2613be50 n_tty: Fix stale ... |
1806 |
if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) { |
dab73b4eb TTY: Fix tty miss... |
1807 |
start_tty(tty); |
e2613be50 n_tty: Fix stale ... |
1808 1809 |
process_echoes(tty); } |
dab73b4eb TTY: Fix tty miss... |
1810 |
|
f34d7a5b7 tty: The big oper... |
1811 |
/* The termios change make the tty ready for I/O */ |
e81107d4c tty: fix stall ca... |
1812 1813 |
wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); |
1da177e4c Linux-2.6.12-rc2 |
1814 1815 1816 1817 1818 1819 |
} /** * n_tty_close - close the ldisc for this tty * @tty: device * |
4edf1827e n_tty: clean up o... |
1820 1821 |
* Called from the terminal layer when this line discipline is * being shut down, either because of a close or becsuse of a |
1da177e4c Linux-2.6.12-rc2 |
1822 1823 1824 |
* discipline change. The function will not be called while other * ldisc methods are in progress. */ |
4edf1827e n_tty: clean up o... |
1825 |
|
1da177e4c Linux-2.6.12-rc2 |
1826 1827 |
static void n_tty_close(struct tty_struct *tty) { |
70ece7a73 TTY: n_tty, add l... |
1828 |
struct n_tty_data *ldata = tty->disc_data; |
79901317c n_tty: Don't flus... |
1829 1830 |
if (tty->link) n_tty_packet_mode_flush(tty); |
20bafb3d2 n_tty: Move buffe... |
1831 |
vfree(ldata); |
70ece7a73 TTY: n_tty, add l... |
1832 |
tty->disc_data = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1833 1834 1835 1836 1837 1838 |
} /** * n_tty_open - open an ldisc * @tty: terminal to open * |
4edf1827e n_tty: clean up o... |
1839 |
* Called when this line discipline is being attached to the |
1da177e4c Linux-2.6.12-rc2 |
1840 1841 1842 1843 1844 1845 1846 |
* terminal device. Can sleep. Called serialized so that no * other events will occur in parallel. No further open will occur * until a close. */ static int n_tty_open(struct tty_struct *tty) { |
70ece7a73 TTY: n_tty, add l... |
1847 |
struct n_tty_data *ldata; |
20bafb3d2 n_tty: Move buffe... |
1848 |
/* Currently a malloc failure here can panic */ |
ebec3f8f5 n_tty: Access ech... |
1849 |
ldata = vzalloc(sizeof(*ldata)); |
70ece7a73 TTY: n_tty, add l... |
1850 |
if (!ldata) |
ebec3f8f5 n_tty: Access ech... |
1851 |
return -ENOMEM; |
70ece7a73 TTY: n_tty, add l... |
1852 |
|
53c5ee2cf TTY: move ldisc d... |
1853 |
ldata->overrun_time = jiffies; |
bddc7152f TTY: move ldisc d... |
1854 1855 |
mutex_init(&ldata->atomic_read_lock); mutex_init(&ldata->output_lock); |
53c5ee2cf TTY: move ldisc d... |
1856 |
|
70ece7a73 TTY: n_tty, add l... |
1857 |
tty->disc_data = ldata; |
1da177e4c Linux-2.6.12-rc2 |
1858 |
tty->closing = 0; |
b66f4fa50 n_tty: Fully init... |
1859 1860 1861 1862 |
/* indicate buffer work may resume */ clear_bit(TTY_LDISC_HALTED, &tty->flags); n_tty_set_termios(tty, NULL); tty_unthrottle(tty); |
1da177e4c Linux-2.6.12-rc2 |
1863 1864 |
return 0; } |
eafbe67f8 n_tty: Refactor i... |
1865 |
static inline int input_available_p(struct tty_struct *tty, int poll) |
1da177e4c Linux-2.6.12-rc2 |
1866 |
{ |
53c5ee2cf TTY: move ldisc d... |
1867 |
struct n_tty_data *ldata = tty->disc_data; |
a5934804a n_tty: Fix poll()... |
1868 |
int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1; |
53c5ee2cf TTY: move ldisc d... |
1869 |
|
25e8d0ed7 n_tty: Simplify i... |
1870 1871 1872 |
if (ldata->icanon && !L_EXTPROC(tty)) return ldata->canon_head != ldata->read_tail; else |
70aca71f9 n_tty: Fix unorde... |
1873 |
return ldata->commit_head - ldata->read_tail >= amt; |
1da177e4c Linux-2.6.12-rc2 |
1874 1875 1876 |
} /** |
bbd20759d drivers/tty: Remo... |
1877 |
* copy_from_read_buf - copy read data directly |
1da177e4c Linux-2.6.12-rc2 |
1878 1879 1880 1881 |
* @tty: terminal device * @b: user data * @nr: size of data * |
11a96d182 tty: rename the r... |
1882 |
* Helper function to speed up n_tty_read. It is only called when |
1da177e4c Linux-2.6.12-rc2 |
1883 1884 1885 1886 1887 1888 |
* ICANON is off; it copies characters straight from the tty queue to * user space directly. It can be profitably called twice; once to * drain the space from the tail pointer to the (physical) end of the * buffer, and once to drain the space from the (physical) beginning of * the buffer to head pointer. * |
bddc7152f TTY: move ldisc d... |
1889 |
* Called under the ldata->atomic_read_lock sem |
1da177e4c Linux-2.6.12-rc2 |
1890 |
* |
6d76bd261 n_tty: Make N_TTY... |
1891 1892 1893 |
* n_tty_read()/consumer path: * caller holds non-exclusive termios_rwsem * read_tail published |
1da177e4c Linux-2.6.12-rc2 |
1894 |
*/ |
4edf1827e n_tty: clean up o... |
1895 |
|
33f0f88f1 [PATCH] TTY layer... |
1896 |
static int copy_from_read_buf(struct tty_struct *tty, |
1da177e4c Linux-2.6.12-rc2 |
1897 1898 1899 1900 |
unsigned char __user **b, size_t *nr) { |
53c5ee2cf TTY: move ldisc d... |
1901 |
struct n_tty_data *ldata = tty->disc_data; |
1da177e4c Linux-2.6.12-rc2 |
1902 1903 |
int retval; size_t n; |
3fa10cc83 TTY: n_tty, do no... |
1904 |
bool is_eof; |
70aca71f9 n_tty: Fix unorde... |
1905 |
size_t head = smp_load_acquire(&ldata->commit_head); |
bc5a5e3f4 n_tty: Don't wrap... |
1906 |
size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); |
1da177e4c Linux-2.6.12-rc2 |
1907 1908 |
retval = 0; |
70aca71f9 n_tty: Fix unorde... |
1909 |
n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail); |
1da177e4c Linux-2.6.12-rc2 |
1910 |
n = min(*nr, n); |
1da177e4c Linux-2.6.12-rc2 |
1911 |
if (n) { |
b97b3d9fb tty: wipe buffer ... |
1912 |
unsigned char *from = read_buf_addr(ldata, tail); |
e661cf702 n_tty: Clarify co... |
1913 |
retval = copy_to_user(*b, from, n); |
1da177e4c Linux-2.6.12-rc2 |
1914 |
n -= retval; |
e661cf702 n_tty: Clarify co... |
1915 |
is_eof = n == 1 && *from == EOF_CHAR(tty); |
309426ae6 tty: audit: Remov... |
1916 |
tty_audit_add_data(tty, from, n); |
b97b3d9fb tty: wipe buffer ... |
1917 |
zero_buffer(tty, from, n); |
70aca71f9 n_tty: Fix unorde... |
1918 |
smp_store_release(&ldata->read_tail, ldata->read_tail + n); |
26df6d134 tty: Add EXTPROC ... |
1919 |
/* Turn single EOF into zero-length read */ |
70aca71f9 n_tty: Fix unorde... |
1920 1921 |
if (L_EXTPROC(tty) && ldata->icanon && is_eof && (head == ldata->read_tail)) |
3fa10cc83 TTY: n_tty, do no... |
1922 |
n = 0; |
1da177e4c Linux-2.6.12-rc2 |
1923 1924 1925 1926 1927 |
*b += n; *nr -= n; } return retval; } |
88bb0de38 n_tty: Factor can... |
1928 |
/** |
32f13521c n_tty: Line copy ... |
1929 |
* canon_copy_from_read_buf - copy read data in canonical mode |
88bb0de38 n_tty: Factor can... |
1930 1931 1932 1933 1934 |
* @tty: terminal device * @b: user data * @nr: size of data * * Helper function for n_tty_read. It is only called when ICANON is on; |
32f13521c n_tty: Line copy ... |
1935 1936 |
* it copies one line of input up to and including the line-delimiting * character into the user-space buffer. |
88bb0de38 n_tty: Factor can... |
1937 |
* |
4d0ed1827 n_tty: Fix buffer... |
1938 1939 1940 1941 1942 1943 |
* NB: When termios is changed from non-canonical to canonical mode and * the read buffer contains data, n_tty_set_termios() simulates an EOF * push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer. * This causes data already processed as input to be immediately available * as input although a newline has not been received. * |
88bb0de38 n_tty: Factor can... |
1944 |
* Called under the atomic_read_lock mutex |
6d76bd261 n_tty: Make N_TTY... |
1945 1946 1947 1948 |
* * n_tty_read()/consumer path: * caller holds non-exclusive termios_rwsem * read_tail published |
88bb0de38 n_tty: Factor can... |
1949 |
*/ |
32f13521c n_tty: Line copy ... |
1950 1951 1952 |
static int canon_copy_from_read_buf(struct tty_struct *tty, unsigned char __user **b, size_t *nr) |
88bb0de38 n_tty: Factor can... |
1953 1954 |
{ struct n_tty_data *ldata = tty->disc_data; |
32f13521c n_tty: Line copy ... |
1955 |
size_t n, size, more, c; |
bc5a5e3f4 n_tty: Don't wrap... |
1956 1957 1958 |
size_t eol; size_t tail; int ret, found = 0; |
88bb0de38 n_tty: Factor can... |
1959 1960 |
/* N.B. avoid overrun if nr == 0 */ |
ac8f3bf88 n_tty: Fix poll()... |
1961 |
if (!*nr) |
32f13521c n_tty: Line copy ... |
1962 |
return 0; |
88bb0de38 n_tty: Factor can... |
1963 |
|
ac8f3bf88 n_tty: Fix poll()... |
1964 |
n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail); |
bc5a5e3f4 n_tty: Don't wrap... |
1965 |
tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); |
32f13521c n_tty: Line copy ... |
1966 |
size = min_t(size_t, tail + n, N_TTY_BUF_SIZE); |
bc5a5e3f4 n_tty: Don't wrap... |
1967 1968 |
n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu ", |
32f13521c n_tty: Line copy ... |
1969 1970 1971 1972 1973 1974 1975 |
__func__, *nr, tail, n, size); eol = find_next_bit(ldata->read_flags, size, tail); more = n - (size - tail); if (eol == N_TTY_BUF_SIZE && more) { /* scan wrapped without finding set bit */ eol = find_next_bit(ldata->read_flags, more, 0); |
b985e9e36 n_tty: Reduce bra... |
1976 1977 1978 |
found = eol != more; } else found = eol != size; |
32f13521c n_tty: Line copy ... |
1979 |
|
c77569d2f n_tty: Fix 4096-b... |
1980 |
n = eol - tail; |
da555db6b n_tty: Fix calcul... |
1981 1982 |
if (n > N_TTY_BUF_SIZE) n += N_TTY_BUF_SIZE; |
ac8f3bf88 n_tty: Fix poll()... |
1983 |
c = n + found; |
32f13521c n_tty: Line copy ... |
1984 |
|
ac8f3bf88 n_tty: Fix poll()... |
1985 1986 1987 |
if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) { c = min(*nr, c); n = c; |
40d5e0905 n_tty: Fix EOF pu... |
1988 |
} |
32f13521c n_tty: Line copy ... |
1989 |
|
679e7c299 n_tty: Uninline t... |
1990 1991 1992 |
n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu ", __func__, eol, found, n, c, tail, more); |
32f13521c n_tty: Line copy ... |
1993 |
|
679e7c299 n_tty: Uninline t... |
1994 |
ret = tty_copy_to_user(tty, *b, tail, n); |
32f13521c n_tty: Line copy ... |
1995 1996 1997 1998 |
if (ret) return -EFAULT; *b += n; *nr -= n; |
a73d3d698 n_tty: Replace ca... |
1999 |
if (found) |
6d76bd261 n_tty: Make N_TTY... |
2000 |
clear_bit(eol, ldata->read_flags); |
70aca71f9 n_tty: Fix unorde... |
2001 |
smp_store_release(&ldata->read_tail, ldata->read_tail + c); |
88bb0de38 n_tty: Factor can... |
2002 |
|
40d5e0905 n_tty: Fix EOF pu... |
2003 |
if (found) { |
4d0ed1827 n_tty: Fix buffer... |
2004 2005 2006 2007 |
if (!ldata->push) ldata->line_start = ldata->read_tail; else ldata->push = 0; |
b50819f43 tty: audit: Ignor... |
2008 |
tty_audit_push(); |
40d5e0905 n_tty: Fix EOF pu... |
2009 |
} |
ac8f3bf88 n_tty: Fix poll()... |
2010 |
return 0; |
88bb0de38 n_tty: Factor can... |
2011 |
} |
cc4191dc1 drivers/char/n_tt... |
2012 |
extern ssize_t redirected_tty_write(struct file *, const char __user *, |
4edf1827e n_tty: clean up o... |
2013 |
size_t, loff_t *); |
1da177e4c Linux-2.6.12-rc2 |
2014 2015 2016 2017 2018 2019 2020 |
/** * job_control - check job control * @tty: tty * @file: file handle * * Perform job control management checks on this file/tty descriptor |
4edf1827e n_tty: clean up o... |
2021 |
* and if appropriate send any needed signals and return a negative |
1da177e4c Linux-2.6.12-rc2 |
2022 |
* error code if action should be taken. |
04f378b19 tty: BKL pushdown |
2023 |
* |
01a5e440c n_tty: Lock acces... |
2024 2025 2026 |
* Locking: redirected write test is safe * current->signal->tty check is safe * ctrl_lock to safely reference tty->pgrp |
1da177e4c Linux-2.6.12-rc2 |
2027 |
*/ |
4edf1827e n_tty: clean up o... |
2028 |
|
1da177e4c Linux-2.6.12-rc2 |
2029 2030 2031 2032 2033 2034 2035 |
static int job_control(struct tty_struct *tty, struct file *file) { /* Job control check -- must be done at start and after every sleep (POSIX.1 7.1.1.4). */ /* NOTE: not yet done after every sleep pending a thorough check of the logic of this change. -- jlc */ /* don't stop on /dev/console */ |
2812d9e9f tty: Combine SIGT... |
2036 |
if (file->f_op->write == redirected_tty_write) |
01a5e440c n_tty: Lock acces... |
2037 |
return 0; |
2812d9e9f tty: Combine SIGT... |
2038 |
return __tty_check_change(tty, SIGTTIN); |
1da177e4c Linux-2.6.12-rc2 |
2039 |
} |
4edf1827e n_tty: clean up o... |
2040 |
|
1da177e4c Linux-2.6.12-rc2 |
2041 2042 |
/** |
11a96d182 tty: rename the r... |
2043 |
* n_tty_read - read function for tty |
1da177e4c Linux-2.6.12-rc2 |
2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 |
* @tty: tty device * @file: file object * @buf: userspace buffer pointer * @nr: size of I/O * * Perform reads for the line discipline. We are guaranteed that the * line discipline will not be closed under us but we may get multiple * parallel readers and must handle this ourselves. We may also get * a hangup. Always called in user context, may sleep. * * This code must be sure never to sleep through a hangup. |
6d76bd261 n_tty: Make N_TTY... |
2055 2056 2057 2058 |
* * n_tty_read()/consumer path: * claims non-exclusive termios_rwsem * publishes read_tail |
1da177e4c Linux-2.6.12-rc2 |
2059 |
*/ |
4edf1827e n_tty: clean up o... |
2060 |
|
11a96d182 tty: rename the r... |
2061 |
static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, |
1da177e4c Linux-2.6.12-rc2 |
2062 2063 |
unsigned char __user *buf, size_t nr) { |
53c5ee2cf TTY: move ldisc d... |
2064 |
struct n_tty_data *ldata = tty->disc_data; |
1da177e4c Linux-2.6.12-rc2 |
2065 |
unsigned char __user *b = buf; |
97d9e28d1 sched, tty: Deal ... |
2066 |
DEFINE_WAIT_FUNC(wait, woken_wake_function); |
0f40fbbcc Fix OpenSSH pty r... |
2067 |
int c; |
1da177e4c Linux-2.6.12-rc2 |
2068 2069 |
int minimum, time; ssize_t retval = 0; |
1da177e4c Linux-2.6.12-rc2 |
2070 |
long timeout; |
04f378b19 tty: BKL pushdown |
2071 |
int packet; |
2c5dc4641 n_tty: Eliminate ... |
2072 |
size_t tail; |
1da177e4c Linux-2.6.12-rc2 |
2073 |
|
1da177e4c Linux-2.6.12-rc2 |
2074 |
c = job_control(tty, file); |
4edf1827e n_tty: clean up o... |
2075 |
if (c < 0) |
1da177e4c Linux-2.6.12-rc2 |
2076 |
return c; |
4edf1827e n_tty: clean up o... |
2077 |
|
aefceaf45 n_tty: Fix termio... |
2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 |
/* * Internal serialization of reads. */ if (file->f_flags & O_NONBLOCK) { if (!mutex_trylock(&ldata->atomic_read_lock)) return -EAGAIN; } else { if (mutex_lock_interruptible(&ldata->atomic_read_lock)) return -ERESTARTSYS; } |
9356b535f n_tty: Access ter... |
2088 |
down_read(&tty->termios_rwsem); |
1da177e4c Linux-2.6.12-rc2 |
2089 2090 |
minimum = time = 0; timeout = MAX_SCHEDULE_TIMEOUT; |
53c5ee2cf TTY: move ldisc d... |
2091 |
if (!ldata->icanon) { |
1da177e4c Linux-2.6.12-rc2 |
2092 2093 |
minimum = MIN_CHAR(tty); if (minimum) { |
a6e54319a n_tty: Untangle r... |
2094 |
time = (HZ / 10) * TIME_CHAR(tty); |
1da177e4c Linux-2.6.12-rc2 |
2095 |
} else { |
a6e54319a n_tty: Untangle r... |
2096 |
timeout = (HZ / 10) * TIME_CHAR(tty); |
33d713633 n_tty: Always wak... |
2097 |
minimum = 1; |
1da177e4c Linux-2.6.12-rc2 |
2098 2099 |
} } |
04f378b19 tty: BKL pushdown |
2100 |
packet = tty->packet; |
2c5dc4641 n_tty: Eliminate ... |
2101 |
tail = ldata->read_tail; |
1da177e4c Linux-2.6.12-rc2 |
2102 2103 |
add_wait_queue(&tty->read_wait, &wait); |
1da177e4c Linux-2.6.12-rc2 |
2104 2105 |
while (nr) { /* First test for status change. */ |
04f378b19 tty: BKL pushdown |
2106 |
if (packet && tty->link->ctrl_status) { |
1da177e4c Linux-2.6.12-rc2 |
2107 2108 2109 |
unsigned char cs; if (b != buf) break; |
6054c16e8 tty: Use spin_loc... |
2110 |
spin_lock_irq(&tty->link->ctrl_lock); |
1da177e4c Linux-2.6.12-rc2 |
2111 2112 |
cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; |
6054c16e8 tty: Use spin_loc... |
2113 |
spin_unlock_irq(&tty->link->ctrl_lock); |
eab25a5cd tty: audit: Never... |
2114 |
if (put_user(cs, b)) { |
1da177e4c Linux-2.6.12-rc2 |
2115 |
retval = -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
2116 2117 |
break; } |
eab25a5cd tty: audit: Never... |
2118 |
b++; |
1da177e4c Linux-2.6.12-rc2 |
2119 2120 2121 |
nr--; break; } |
4edf1827e n_tty: clean up o... |
2122 |
|
1da177e4c Linux-2.6.12-rc2 |
2123 |
if (!input_available_p(tty, 0)) { |
52bce7f8d pty, n_tty: Simpl... |
2124 |
up_read(&tty->termios_rwsem); |
0f40fbbcc Fix OpenSSH pty r... |
2125 2126 2127 2128 2129 2130 2131 2132 2133 |
tty_buffer_flush_work(tty->port); down_read(&tty->termios_rwsem); if (!input_available_p(tty, 0)) { if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { retval = -EIO; break; } if (tty_hung_up_p(file)) break; |
28b0f8a69 tty: make n_tty_r... |
2134 2135 2136 2137 2138 2139 |
/* * Abort readers for ttys which never actually * get hung up. See __tty_hangup(). */ if (test_bit(TTY_HUPPING, &tty->flags)) break; |
0f40fbbcc Fix OpenSSH pty r... |
2140 2141 |
if (!timeout) break; |
c96cf923a tty: Don't block ... |
2142 |
if (tty_io_nonblock(tty, file)) { |
0f40fbbcc Fix OpenSSH pty r... |
2143 2144 2145 2146 2147 2148 2149 2150 |
retval = -EAGAIN; break; } if (signal_pending(current)) { retval = -ERESTARTSYS; break; } up_read(&tty->termios_rwsem); |
9356b535f n_tty: Access ter... |
2151 |
|
0f40fbbcc Fix OpenSSH pty r... |
2152 2153 |
timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, timeout); |
9356b535f n_tty: Access ter... |
2154 |
|
0f40fbbcc Fix OpenSSH pty r... |
2155 2156 2157 |
down_read(&tty->termios_rwsem); continue; } |
1da177e4c Linux-2.6.12-rc2 |
2158 |
} |
53c5ee2cf TTY: move ldisc d... |
2159 |
if (ldata->icanon && !L_EXTPROC(tty)) { |
32f13521c n_tty: Line copy ... |
2160 |
retval = canon_copy_from_read_buf(tty, &b, &nr); |
ac8f3bf88 n_tty: Fix poll()... |
2161 |
if (retval) |
1da177e4c Linux-2.6.12-rc2 |
2162 2163 2164 |
break; } else { int uncopied; |
95ea90db0 n_tty: Only proce... |
2165 2166 2167 |
/* Deal with packet mode. */ if (packet && b == buf) { |
eab25a5cd tty: audit: Never... |
2168 |
if (put_user(TIOCPKT_DATA, b)) { |
95ea90db0 n_tty: Only proce... |
2169 |
retval = -EFAULT; |
95ea90db0 n_tty: Only proce... |
2170 2171 |
break; } |
eab25a5cd tty: audit: Never... |
2172 |
b++; |
95ea90db0 n_tty: Only proce... |
2173 2174 |
nr--; } |
1da177e4c Linux-2.6.12-rc2 |
2175 2176 2177 2178 2179 2180 2181 |
uncopied = copy_from_read_buf(tty, &b, &nr); uncopied += copy_from_read_buf(tty, &b, &nr); if (uncopied) { retval = -EFAULT; break; } } |
6367ca72f n_tty: Factor thr... |
2182 |
n_tty_check_unthrottle(tty); |
1da177e4c Linux-2.6.12-rc2 |
2183 2184 2185 2186 2187 2188 |
if (b - buf >= minimum) break; if (time) timeout = time; } |
2c5dc4641 n_tty: Eliminate ... |
2189 2190 |
if (tail != ldata->read_tail) n_tty_kick_worker(tty); |
42458f41d n_tty: Ensure rea... |
2191 |
up_read(&tty->termios_rwsem); |
1da177e4c Linux-2.6.12-rc2 |
2192 |
remove_wait_queue(&tty->read_wait, &wait); |
aebf04538 n_tty: Protect mi... |
2193 |
mutex_unlock(&ldata->atomic_read_lock); |
40d5e0905 n_tty: Fix EOF pu... |
2194 2195 |
if (b - buf) retval = b - buf; |
1da177e4c Linux-2.6.12-rc2 |
2196 2197 2198 2199 2200 |
return retval; } /** |
11a96d182 tty: rename the r... |
2201 |
* n_tty_write - write function for tty |
1da177e4c Linux-2.6.12-rc2 |
2202 2203 2204 2205 2206 |
* @tty: tty device * @file: file object * @buf: userspace buffer pointer * @nr: size of I/O * |
a88a69c91 n_tty: Fix loss o... |
2207 |
* Write function of the terminal device. This is serialized with |
1da177e4c Linux-2.6.12-rc2 |
2208 |
* respect to other write callers but not to termios changes, reads |
a88a69c91 n_tty: Fix loss o... |
2209 2210 2211 2212 2213 |
* and other such events. Since the receive code will echo characters, * thus calling driver write methods, the output_lock is used in * the output processing functions called here as well as in the * echo processing function to protect the column state and space * left in the buffer. |
1da177e4c Linux-2.6.12-rc2 |
2214 2215 |
* * This code must be sure never to sleep through a hangup. |
a88a69c91 n_tty: Fix loss o... |
2216 2217 2218 2219 |
* * Locking: output_lock to protect column state and space left * (note that the process_output*() functions take this * lock themselves) |
1da177e4c Linux-2.6.12-rc2 |
2220 |
*/ |
4edf1827e n_tty: clean up o... |
2221 |
|
11a96d182 tty: rename the r... |
2222 |
static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, |
a88a69c91 n_tty: Fix loss o... |
2223 |
const unsigned char *buf, size_t nr) |
1da177e4c Linux-2.6.12-rc2 |
2224 2225 |
{ const unsigned char *b = buf; |
97d9e28d1 sched, tty: Deal ... |
2226 |
DEFINE_WAIT_FUNC(wait, woken_wake_function); |
1da177e4c Linux-2.6.12-rc2 |
2227 2228 2229 2230 2231 2232 2233 2234 2235 |
int c; ssize_t retval = 0; /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) { retval = tty_check_change(tty); if (retval) return retval; } |
9356b535f n_tty: Access ter... |
2236 |
down_read(&tty->termios_rwsem); |
a88a69c91 n_tty: Fix loss o... |
2237 2238 |
/* Write out any echoed characters that are still pending */ process_echoes(tty); |
300a6204b n_tty: clean up c... |
2239 |
|
1da177e4c Linux-2.6.12-rc2 |
2240 2241 |
add_wait_queue(&tty->write_wait, &wait); while (1) { |
1da177e4c Linux-2.6.12-rc2 |
2242 2243 2244 2245 2246 2247 2248 2249 |
if (signal_pending(current)) { retval = -ERESTARTSYS; break; } if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { retval = -EIO; break; } |
582f55907 tty: Remove TTY_H... |
2250 |
if (O_OPOST(tty)) { |
1da177e4c Linux-2.6.12-rc2 |
2251 |
while (nr > 0) { |
a88a69c91 n_tty: Fix loss o... |
2252 |
ssize_t num = process_output_block(tty, b, nr); |
1da177e4c Linux-2.6.12-rc2 |
2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 |
if (num < 0) { if (num == -EAGAIN) break; retval = num; goto break_out; } b += num; nr -= num; if (nr == 0) break; c = *b; |
a88a69c91 n_tty: Fix loss o... |
2264 |
if (process_output(c, tty) < 0) |
1da177e4c Linux-2.6.12-rc2 |
2265 2266 2267 |
break; b++; nr--; } |
f34d7a5b7 tty: The big oper... |
2268 2269 |
if (tty->ops->flush_chars) tty->ops->flush_chars(tty); |
1da177e4c Linux-2.6.12-rc2 |
2270 |
} else { |
4291086b1 n_tty: Fix n_tty_... |
2271 |
struct n_tty_data *ldata = tty->disc_data; |
d6afe27bf [PATCH] tty outpu... |
2272 |
while (nr > 0) { |
4291086b1 n_tty: Fix n_tty_... |
2273 |
mutex_lock(&ldata->output_lock); |
f34d7a5b7 tty: The big oper... |
2274 |
c = tty->ops->write(tty, b, nr); |
4291086b1 n_tty: Fix n_tty_... |
2275 |
mutex_unlock(&ldata->output_lock); |
d6afe27bf [PATCH] tty outpu... |
2276 2277 2278 2279 2280 2281 2282 2283 |
if (c < 0) { retval = c; goto break_out; } if (!c) break; b += c; nr -= c; |
1da177e4c Linux-2.6.12-rc2 |
2284 |
} |
1da177e4c Linux-2.6.12-rc2 |
2285 2286 2287 |
} if (!nr) break; |
c96cf923a tty: Don't block ... |
2288 |
if (tty_io_nonblock(tty, file)) { |
1da177e4c Linux-2.6.12-rc2 |
2289 2290 2291 |
retval = -EAGAIN; break; } |
9356b535f n_tty: Access ter... |
2292 |
up_read(&tty->termios_rwsem); |
97d9e28d1 sched, tty: Deal ... |
2293 |
wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); |
9356b535f n_tty: Access ter... |
2294 2295 |
down_read(&tty->termios_rwsem); |
1da177e4c Linux-2.6.12-rc2 |
2296 2297 |
} break_out: |
1da177e4c Linux-2.6.12-rc2 |
2298 |
remove_wait_queue(&tty->write_wait, &wait); |
87108bc98 tty: n_tty: fix S... |
2299 |
if (nr && tty->fasync) |
ff8cb0fd6 tty: N_TTY SIGIO ... |
2300 |
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); |
9356b535f n_tty: Access ter... |
2301 |
up_read(&tty->termios_rwsem); |
1da177e4c Linux-2.6.12-rc2 |
2302 2303 2304 2305 |
return (b - buf) ? b - buf : retval; } /** |
11a96d182 tty: rename the r... |
2306 |
* n_tty_poll - poll method for N_TTY |
1da177e4c Linux-2.6.12-rc2 |
2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 |
* @tty: terminal device * @file: file accessing it * @wait: poll table * * Called when the line discipline is asked to poll() for data or * for special events. This code is not serialized with respect to * other events save open/close. * * This code must be sure never to sleep through a hangup. * Called without the kernel lock held - fine |
1da177e4c Linux-2.6.12-rc2 |
2317 |
*/ |
4edf1827e n_tty: clean up o... |
2318 |
|
afc9a42b7 the rest of drive... |
2319 |
static __poll_t n_tty_poll(struct tty_struct *tty, struct file *file, |
4edf1827e n_tty: clean up o... |
2320 |
poll_table *wait) |
1da177e4c Linux-2.6.12-rc2 |
2321 |
{ |
afc9a42b7 the rest of drive... |
2322 |
__poll_t mask = 0; |
1da177e4c Linux-2.6.12-rc2 |
2323 2324 2325 |
poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->write_wait, wait); |
eafbe67f8 n_tty: Refactor i... |
2326 |
if (input_available_p(tty, 1)) |
a9a08845e vfs: do bulk POLL... |
2327 |
mask |= EPOLLIN | EPOLLRDNORM; |
0f40fbbcc Fix OpenSSH pty r... |
2328 2329 2330 |
else { tty_buffer_flush_work(tty->port); if (input_available_p(tty, 1)) |
a9a08845e vfs: do bulk POLL... |
2331 |
mask |= EPOLLIN | EPOLLRDNORM; |
0f40fbbcc Fix OpenSSH pty r... |
2332 |
} |
1da177e4c Linux-2.6.12-rc2 |
2333 |
if (tty->packet && tty->link->ctrl_status) |
a9a08845e vfs: do bulk POLL... |
2334 |
mask |= EPOLLPRI | EPOLLIN | EPOLLRDNORM; |
0f40fbbcc Fix OpenSSH pty r... |
2335 |
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) |
a9a08845e vfs: do bulk POLL... |
2336 |
mask |= EPOLLHUP; |
1da177e4c Linux-2.6.12-rc2 |
2337 |
if (tty_hung_up_p(file)) |
a9a08845e vfs: do bulk POLL... |
2338 |
mask |= EPOLLHUP; |
f34d7a5b7 tty: The big oper... |
2339 2340 2341 |
if (tty->ops->write && !tty_is_writelocked(tty) && tty_chars_in_buffer(tty) < WAKEUP_CHARS && tty_write_room(tty) > 0) |
a9a08845e vfs: do bulk POLL... |
2342 |
mask |= EPOLLOUT | EPOLLWRNORM; |
1da177e4c Linux-2.6.12-rc2 |
2343 2344 |
return mask; } |
57c941212 TTY: n_tty, propa... |
2345 |
static unsigned long inq_canon(struct n_tty_data *ldata) |
47afa7a5a tty: some ICANON ... |
2346 |
{ |
bc5a5e3f4 n_tty: Don't wrap... |
2347 |
size_t nr, head, tail; |
47afa7a5a tty: some ICANON ... |
2348 |
|
a73d3d698 n_tty: Replace ca... |
2349 |
if (ldata->canon_head == ldata->read_tail) |
47afa7a5a tty: some ICANON ... |
2350 |
return 0; |
ba2e68ac6 TTY: move ldisc d... |
2351 2352 |
head = ldata->canon_head; tail = ldata->read_tail; |
bc5a5e3f4 n_tty: Don't wrap... |
2353 |
nr = head - tail; |
47afa7a5a tty: some ICANON ... |
2354 |
/* Skip EOF-chars.. */ |
3d63b7e4a n_tty: Fix stall ... |
2355 |
while (MASK(head) != MASK(tail)) { |
bc5a5e3f4 n_tty: Don't wrap... |
2356 2357 |
if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) && read_buf(ldata, tail) == __DISABLED_CHAR) |
47afa7a5a tty: some ICANON ... |
2358 |
nr--; |
bc5a5e3f4 n_tty: Don't wrap... |
2359 |
tail++; |
47afa7a5a tty: some ICANON ... |
2360 2361 2362 2363 2364 2365 2366 |
} return nr; } static int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { |
ba2e68ac6 TTY: move ldisc d... |
2367 |
struct n_tty_data *ldata = tty->disc_data; |
47afa7a5a tty: some ICANON ... |
2368 2369 2370 2371 2372 2373 |
int retval; switch (cmd) { case TIOCOUTQ: return put_user(tty_chars_in_buffer(tty), (int __user *) arg); case TIOCINQ: |
6d76bd261 n_tty: Make N_TTY... |
2374 |
down_write(&tty->termios_rwsem); |
966031f34 n_tty: fix EXTPRO... |
2375 |
if (L_ICANON(tty) && !L_EXTPROC(tty)) |
57c941212 TTY: n_tty, propa... |
2376 |
retval = inq_canon(ldata); |
6d76bd261 n_tty: Make N_TTY... |
2377 2378 2379 |
else retval = read_cnt(ldata); up_write(&tty->termios_rwsem); |
47afa7a5a tty: some ICANON ... |
2380 2381 2382 2383 2384 |
return put_user(retval, (unsigned int __user *) arg); default: return n_tty_ioctl_helper(tty, file, cmd, arg); } } |
27228732a tty: Eliminate gl... |
2385 |
static struct tty_ldisc_ops n_tty_ops = { |
e10cc1df1 tty: add compat_i... |
2386 2387 2388 2389 2390 |
.magic = TTY_LDISC_MAGIC, .name = "n_tty", .open = n_tty_open, .close = n_tty_close, .flush_buffer = n_tty_flush_buffer, |
11a96d182 tty: rename the r... |
2391 2392 |
.read = n_tty_read, .write = n_tty_write, |
e10cc1df1 tty: add compat_i... |
2393 2394 |
.ioctl = n_tty_ioctl, .set_termios = n_tty_set_termios, |
11a96d182 tty: rename the r... |
2395 |
.poll = n_tty_poll, |
e10cc1df1 tty: add compat_i... |
2396 |
.receive_buf = n_tty_receive_buf, |
f6c8dbe6e n_tty: Encapsulat... |
2397 |
.write_wakeup = n_tty_write_wakeup, |
24a89d1cb tty: Make ldisc i... |
2398 |
.receive_buf2 = n_tty_receive_buf2, |
1da177e4c Linux-2.6.12-rc2 |
2399 |
}; |
572b9adbd ldisc n_tty: add ... |
2400 2401 2402 2403 2404 |
/** * n_tty_inherit_ops - inherit N_TTY methods * @ops: struct tty_ldisc_ops where to save N_TTY methods * |
27228732a tty: Eliminate gl... |
2405 |
* Enables a 'subclass' line discipline to 'inherit' N_TTY methods. |
572b9adbd ldisc n_tty: add ... |
2406 2407 2408 2409 |
*/ void n_tty_inherit_ops(struct tty_ldisc_ops *ops) { |
27228732a tty: Eliminate gl... |
2410 |
*ops = n_tty_ops; |
572b9adbd ldisc n_tty: add ... |
2411 2412 2413 2414 |
ops->owner = NULL; ops->refcount = ops->flags = 0; } EXPORT_SYMBOL_GPL(n_tty_inherit_ops); |
27228732a tty: Eliminate gl... |
2415 2416 2417 2418 2419 |
void __init n_tty_init(void) { tty_register_ldisc(N_TTY, &n_tty_ops); } |