]>
Commit | Line | Data |
---|---|---|
2cf5f602 KT |
1 | diff -urN linux-2.2.26.orig/drivers/char/cyclades.c linux-2.2.26/drivers/char/cyclades.c |
2 | --- linux-2.2.26.orig/drivers/char/cyclades.c 2001-11-02 17:39:06.000000000 +0100 | |
3 | +++ linux-2.2.26/drivers/char/cyclades.c 2004-10-25 00:41:47.000000000 +0200 | |
4 | @@ -1019,10 +1019,7 @@ | |
5 | wake_up_interruptible(&info->delta_msr_wait); | |
6 | } | |
7 | if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { | |
8 | - if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) | |
9 | - && tty->ldisc.write_wakeup){ | |
10 | - (tty->ldisc.write_wakeup)(tty); | |
11 | - } | |
12 | + tty_wakeup(tty); | |
13 | wake_up_interruptible(&tty->write_wait); | |
14 | wake_up_interruptible(&tty->poll_wait); | |
15 | } | |
16 | @@ -2821,6 +2818,7 @@ | |
17 | cy_close(struct tty_struct *tty, struct file *filp) | |
18 | { | |
19 | struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; | |
20 | + struct tty_ldisc *ld; | |
21 | unsigned long flags; | |
22 | ||
23 | #ifdef CY_DEBUG_OTHER | |
24 | @@ -2938,8 +2936,12 @@ | |
25 | shutdown(info); | |
26 | if (tty->driver.flush_buffer) | |
27 | tty->driver.flush_buffer(tty); | |
28 | - if (tty->ldisc.flush_buffer) | |
29 | - tty->ldisc.flush_buffer(tty); | |
30 | + ld = tty_ldisc_ref(tty); | |
31 | + if (ld) { | |
32 | + if (ld->flush_buffer) | |
33 | + ld->flush_buffer(tty); | |
34 | + tty_ldisc_deref(ld); | |
35 | + } | |
36 | CY_LOCK(info, flags); | |
37 | ||
38 | tty->closing = 0; | |
39 | @@ -4701,11 +4703,9 @@ | |
40 | } | |
41 | CY_UNLOCK(info, flags); | |
42 | } | |
43 | + tty_wakeup(tty); | |
44 | wake_up_interruptible(&tty->write_wait); | |
45 | wake_up_interruptible(&tty->poll_wait); | |
46 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) | |
47 | - && tty->ldisc.write_wakeup) | |
48 | - (tty->ldisc.write_wakeup)(tty); | |
49 | } /* cy_flush_buffer */ | |
50 | ||
51 | ||
52 | diff -urN linux-2.2.26.orig/drivers/char/dz.c linux-2.2.26/drivers/char/dz.c | |
53 | --- linux-2.2.26.orig/drivers/char/dz.c 2001-03-25 18:31:27.000000000 +0200 | |
54 | +++ linux-2.2.26/drivers/char/dz.c 2004-10-31 09:32:57.000000000 +0100 | |
55 | @@ -1084,10 +1084,10 @@ | |
56 | info->event = 0; | |
57 | info->tty = 0; | |
58 | ||
59 | - if (tty->ldisc.num != ldiscs[N_TTY].num) { | |
60 | + if (tty->ldisc.num != N_TTY) { | |
61 | if (tty->ldisc.close) | |
62 | (tty->ldisc.close)(tty); | |
63 | - tty->ldisc = ldiscs[N_TTY]; | |
64 | + tty->ldisc = *(tty_ldisc_get(N_TTY)); | |
65 | tty->termios->c_line = N_TTY; | |
66 | if (tty->ldisc.open) | |
67 | (tty->ldisc.open)(tty); | |
68 | diff -urN linux-2.2.26.orig/drivers/char/epca.c linux-2.2.26/drivers/char/epca.c | |
69 | --- linux-2.2.26.orig/drivers/char/epca.c 2001-11-02 17:39:06.000000000 +0100 | |
70 | +++ linux-2.2.26/drivers/char/epca.c 2004-10-25 00:50:02.000000000 +0200 | |
71 | @@ -572,7 +572,8 @@ | |
72 | ||
73 | if ((ch = verifyChannel(tty)) != NULL) | |
74 | { /* Begin if ch != NULL */ | |
75 | - | |
76 | + struct tty_ldisc *ld; | |
77 | + | |
78 | save_flags(flags); | |
79 | cli(); | |
80 | ||
81 | @@ -633,8 +634,12 @@ | |
82 | if (tty->driver.flush_buffer) | |
83 | tty->driver.flush_buffer(tty); | |
84 | ||
85 | - if (tty->ldisc.flush_buffer) | |
86 | - tty->ldisc.flush_buffer(tty); | |
87 | + ld = tty_ldisc_ref(tty); | |
88 | + if (ld != NULL) { | |
89 | + if(ld->flush_buffer) | |
90 | + ld->flush_buffer(tty); | |
91 | + tty_ldisc_deref(ld); | |
92 | + } | |
93 | ||
94 | shutdown(ch); | |
95 | tty->closing = 0; | |
96 | @@ -737,12 +742,20 @@ | |
97 | { /* Begin if ch != NULL */ | |
98 | ||
99 | unsigned long flags; | |
100 | - | |
101 | + struct tty_ldisc *ld; | |
102 | + | |
103 | save_flags(flags); | |
104 | cli(); | |
105 | if (tty->driver.flush_buffer) | |
106 | tty->driver.flush_buffer(tty); | |
107 | ||
108 | + ld = tty_ldisc_ref(tty); | |
109 | + if (ld != NULL) { | |
110 | + if (ld->flush_buffer) | |
111 | + ld->flush_buffer(tty); | |
112 | + tty_ldisc_deref(ld); | |
113 | + } | |
114 | + | |
115 | if (tty->ldisc.flush_buffer) | |
116 | tty->ldisc.flush_buffer(tty); | |
117 | ||
118 | @@ -1227,9 +1240,8 @@ | |
119 | ||
120 | wake_up_interruptible(&tty->write_wait); | |
121 | wake_up_interruptible(&tty->poll_wait); | |
122 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) | |
123 | - (tty->ldisc.write_wakeup)(tty); | |
124 | - | |
125 | + tty_wakeup(tty); | |
126 | + | |
127 | } /* End pc_flush_buffer */ | |
128 | ||
129 | /* ------------------ Begin pc_flush_chars ---------------------- */ | |
130 | @@ -2443,9 +2455,7 @@ | |
131 | { /* Begin if LOWWAIT */ | |
132 | ||
133 | ch->statusflags &= ~LOWWAIT; | |
134 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
135 | - tty->ldisc.write_wakeup) | |
136 | - (tty->ldisc.write_wakeup)(tty); | |
137 | + tty_wakeup(tty); | |
138 | wake_up_interruptible(&tty->write_wait); | |
139 | wake_up_interruptible(&tty->poll_wait); | |
140 | } /* End if LOWWAIT */ | |
141 | @@ -2462,9 +2472,7 @@ | |
142 | { /* Begin if EMPTYWAIT */ | |
143 | ||
144 | ch->statusflags &= ~EMPTYWAIT; | |
145 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
146 | - tty->ldisc.write_wakeup) | |
147 | - (tty->ldisc.write_wakeup)(tty); | |
148 | + tty_wakeup(tty); | |
149 | ||
150 | wake_up_interruptible(&tty->write_wait); | |
151 | wake_up_interruptible(&tty->poll_wait); | |
152 | @@ -3327,6 +3335,7 @@ | |
153 | tty_wait_until_sent(tty, 0); | |
154 | } | |
155 | else | |
156 | + /* ldisc lock already held in ioctl */ | |
157 | { | |
158 | if (tty->ldisc.flush_buffer) | |
159 | tty->ldisc.flush_buffer(tty); | |
160 | diff -urN linux-2.2.26.orig/drivers/char/generic_serial.c linux-2.2.26/drivers/char/generic_serial.c | |
161 | --- linux-2.2.26.orig/drivers/char/generic_serial.c 2001-03-25 18:31:27.000000000 +0200 | |
162 | +++ linux-2.2.26/drivers/char/generic_serial.c 2004-10-31 08:46:56.000000000 +0100 | |
163 | @@ -453,9 +453,7 @@ | |
164 | restore_flags(flags); | |
165 | ||
166 | wake_up_interruptible(&tty->write_wait); | |
167 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
168 | - tty->ldisc.write_wakeup) | |
169 | - (tty->ldisc.write_wakeup)(tty); | |
170 | + tty_wakeup(tty); | |
171 | func_exit (); | |
172 | } | |
173 | ||
174 | @@ -595,9 +593,7 @@ | |
175 | if (!tty) return; | |
176 | ||
177 | if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { | |
178 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
179 | - tty->ldisc.write_wakeup) | |
180 | - (tty->ldisc.write_wakeup)(tty); | |
181 | + tty_wakeup(tty); | |
182 | wake_up_interruptible(&tty->write_wait); | |
183 | } | |
184 | func_exit (); | |
185 | @@ -740,8 +736,9 @@ | |
186 | { | |
187 | unsigned long flags; | |
188 | struct gs_port *port; | |
189 | - | |
190 | - func_enter (); | |
191 | + struct tty_ldisc *ld; | |
192 | + | |
193 | + func_enter(); | |
194 | ||
195 | if (!tty) return; | |
196 | ||
197 | @@ -818,8 +815,12 @@ | |
198 | ||
199 | if (tty->driver.flush_buffer) | |
200 | tty->driver.flush_buffer(tty); | |
201 | - if (tty->ldisc.flush_buffer) | |
202 | - tty->ldisc.flush_buffer(tty); | |
203 | + ld = tty_ldisc_ref(tty); | |
204 | + if (ld != NULL) { | |
205 | + if (ld->flush_buffer) | |
206 | + ld->flush_buffer(tty); | |
207 | + tty_ldisc_deref(ld); | |
208 | + } | |
209 | tty->closing = 0; | |
210 | ||
211 | port->event = 0; | |
212 | diff -urN linux-2.2.26.orig/drivers/char/isicom.c linux-2.2.26/drivers/char/isicom.c | |
213 | --- linux-2.2.26.orig/drivers/char/isicom.c 2001-03-25 18:31:27.000000000 +0200 | |
214 | +++ linux-2.2.26/drivers/char/isicom.c 2004-10-31 08:56:09.000000000 +0100 | |
215 | @@ -621,10 +621,8 @@ | |
216 | ||
217 | if (!tty) | |
218 | return; | |
219 | - | |
220 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
221 | - tty->ldisc.write_wakeup) | |
222 | - (tty->ldisc.write_wakeup)(tty); | |
223 | + | |
224 | + tty_wakeup(tty); | |
225 | wake_up_interruptible(&tty->write_wait); | |
226 | } | |
227 | ||
228 | @@ -1349,7 +1347,8 @@ | |
229 | struct isi_port * port = (struct isi_port *) tty->driver_data; | |
230 | struct isi_board * card; | |
231 | unsigned long flags; | |
232 | - | |
233 | + struct tty_ldisc *ld; | |
234 | + | |
235 | #ifdef ISICOM_DEBUG | |
236 | printk(KERN_DEBUG "ISICOM: Close start!!!.\n"); | |
237 | #endif | |
238 | @@ -1417,6 +1416,12 @@ | |
239 | isicom_shutdown_port(port); | |
240 | if (tty->driver.flush_buffer) | |
241 | tty->driver.flush_buffer(tty); | |
242 | + ld = tty_ldisc_ref(tty); | |
243 | + if (ld != NULL) { | |
244 | + if (ld->flush_buffer) | |
245 | + ld->flush_buffer(tty); | |
246 | + tty_ldisc_deref(ld); | |
247 | + } | |
248 | if (tty->ldisc.flush_buffer) | |
249 | tty->ldisc.flush_buffer(tty); | |
250 | ||
251 | @@ -1912,9 +1917,7 @@ | |
252 | spin_unlock_irqrestore(&card->card_lock, flags); | |
253 | ||
254 | wake_up_interruptible(&tty->write_wait); | |
255 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
256 | - tty->ldisc.write_wakeup) | |
257 | - (tty->ldisc.write_wakeup)(tty); | |
258 | + tty_wakeup(tty); | |
259 | } | |
260 | ||
261 | ||
262 | diff -urN linux-2.2.26.orig/drivers/char/moxa.c linux-2.2.26/drivers/char/moxa.c | |
263 | --- linux-2.2.26.orig/drivers/char/moxa.c 2001-11-02 17:39:06.000000000 +0100 | |
264 | +++ linux-2.2.26/drivers/char/moxa.c 2004-10-31 09:02:00.000000000 +0100 | |
265 | @@ -616,6 +616,7 @@ | |
266 | { | |
267 | struct moxa_str *ch; | |
268 | int port; | |
269 | + struct tty_ldisc *ld; | |
270 | ||
271 | port = PORTNO(tty); | |
272 | if (port == MAX_PORTS) { | |
273 | @@ -673,8 +674,13 @@ | |
274 | ||
275 | if (tty->driver.flush_buffer) | |
276 | tty->driver.flush_buffer(tty); | |
277 | - if (tty->ldisc.flush_buffer) | |
278 | - tty->ldisc.flush_buffer(tty); | |
279 | + | |
280 | + ld = tty_ldisc_ref(tty); | |
281 | + if (ld != NULL) { | |
282 | + if (ld->flush_buffer) | |
283 | + ld->flush_buffer(tty); | |
284 | + tty_ldisc_deref(ld); | |
285 | + } | |
286 | tty->closing = 0; | |
287 | ch->event = 0; | |
288 | ch->tty = 0; | |
289 | @@ -750,9 +756,7 @@ | |
290 | if (ch == NULL) | |
291 | return; | |
292 | MoxaPortFlushData(ch->port, 1); | |
293 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
294 | - tty->ldisc.write_wakeup) | |
295 | - (tty->ldisc.write_wakeup) (tty); | |
296 | + tty_wakeup(tty); | |
297 | wake_up_interruptible(&tty->write_wait); | |
298 | wake_up_interruptible(&tty->poll_wait); | |
299 | } | |
300 | @@ -989,7 +993,6 @@ | |
301 | moxaTimer.function = moxa_poll; | |
302 | moxaTimer.expires = jiffies + (HZ / 50); | |
303 | moxaTimer_on = 1; | |
304 | - add_timer(&moxaTimer); | |
305 | return; | |
306 | } | |
307 | for (card = 0; card < MAX_BOARDS; card++) { | |
308 | @@ -1008,9 +1011,7 @@ | |
309 | if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) { | |
310 | if (!tp->stopped) { | |
311 | ch->statusflags &= ~LOWWAIT; | |
312 | - if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
313 | - tp->ldisc.write_wakeup) | |
314 | - (tp->ldisc.write_wakeup) (tp); | |
315 | + tty_wakeup(tp); | |
316 | wake_up_interruptible(&tp->write_wait); | |
317 | wake_up_interruptible(&tp->poll_wait); | |
318 | } | |
319 | @@ -1199,9 +1200,7 @@ | |
320 | if (ch->tty && (ch->statusflags & EMPTYWAIT)) { | |
321 | if (MoxaPortTxQueue(ch->port) == 0) { | |
322 | ch->statusflags &= ~EMPTYWAIT; | |
323 | - if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
324 | - ch->tty->ldisc.write_wakeup) | |
325 | - (ch->tty->ldisc.write_wakeup) (ch->tty); | |
326 | + tty_wakeup(ch->tty); | |
327 | wake_up_interruptible(&ch->tty->write_wait); | |
328 | wake_up_interruptible(&ch->tty->poll_wait); | |
329 | return; | |
330 | diff -urN linux-2.2.26.orig/drivers/char/mxser.c linux-2.2.26/drivers/char/mxser.c | |
331 | --- linux-2.2.26.orig/drivers/char/mxser.c 2001-03-25 18:31:28.000000000 +0200 | |
332 | +++ linux-2.2.26/drivers/char/mxser.c 2004-10-31 09:06:54.000000000 +0100 | |
333 | @@ -712,9 +712,7 @@ | |
334 | if (!tty) | |
335 | return; | |
336 | if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) { | |
337 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
338 | - tty->ldisc.write_wakeup) | |
339 | - (tty->ldisc.write_wakeup) (tty); | |
340 | + tty_wakeup(tty); | |
341 | wake_up_interruptible(&tty->write_wait); | |
342 | wake_up_interruptible(&tty->poll_wait); | |
343 | } | |
344 | @@ -796,6 +794,7 @@ | |
345 | struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; | |
346 | unsigned long flags; | |
347 | unsigned long timeout; | |
348 | + struct tty_ldisc *ld; | |
349 | ||
350 | if (PORTNO(tty) == MXSER_PORTS) | |
351 | return; | |
352 | @@ -876,6 +875,12 @@ | |
353 | mxser_shutdown(info); | |
354 | if (tty->driver.flush_buffer) | |
355 | tty->driver.flush_buffer(tty); | |
356 | + ld = tty_ldisc_ref(tty); | |
357 | + if (ld) { | |
358 | + if (ld->flush_buffer) | |
359 | + ld->flush_buffer(tty); | |
360 | + tty_ldisc_deref(ld); | |
361 | + } | |
362 | if (tty->ldisc.flush_buffer) | |
363 | tty->ldisc.flush_buffer(tty); | |
364 | tty->closing = 0; | |
365 | @@ -1013,9 +1018,7 @@ | |
366 | restore_flags(flags); | |
367 | wake_up_interruptible(&tty->write_wait); | |
368 | wake_up_interruptible(&tty->poll_wait); | |
369 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
370 | - tty->ldisc.write_wakeup) | |
371 | - (tty->ldisc.write_wakeup) (tty); | |
372 | + tty_wakeup(tty); | |
373 | } | |
374 | ||
375 | static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |
376 | diff -urN linux-2.2.26.orig/drivers/char/n_tty.c linux-2.2.26/drivers/char/n_tty.c | |
377 | --- linux-2.2.26.orig/drivers/char/n_tty.c 2001-03-25 18:31:25.000000000 +0200 | |
378 | +++ linux-2.2.26/drivers/char/n_tty.c 2004-10-31 13:27:14.177336648 +0100 | |
379 | @@ -78,11 +78,18 @@ | |
380 | spin_unlock_irqrestore(&tty->read_lock, flags); | |
381 | } | |
382 | ||
383 | -/* | |
384 | +/* | |
385 | + * check_unthrottle - allow new receive data | |
386 | + * @tty; tty device | |
387 | + * | |
388 | * Check whether to call the driver.unthrottle function. | |
389 | * We test the TTY_THROTTLED bit first so that it always | |
390 | - * indicates the current state. | |
391 | - */ | |
392 | + * indicates the current state. The decision about whether | |
393 | + * it is worth allowing more input has been taken by the caller. | |
394 | + * Can sleep, may be called under the atomic_read semaphore but | |
395 | + * this is not guaranteed. | |
396 | +*/ | |
397 | + | |
398 | static void check_unthrottle(struct tty_struct * tty) | |
399 | { | |
400 | if (tty->count && | |
401 | @@ -92,10 +99,14 @@ | |
402 | } | |
403 | ||
404 | /* | |
405 | + * reset_buffer_flags - reset buffer state | |
406 | + * @tty: terminal to reset | |
407 | + * | |
408 | * Reset the read buffer counters, clear the flags, | |
409 | * and make sure the driver is unthrottled. Called | |
410 | * from n_tty_open() and n_tty_flush_buffer(). | |
411 | */ | |
412 | + | |
413 | static void reset_buffer_flags(struct tty_struct *tty) | |
414 | { | |
415 | unsigned long flags; | |
416 | @@ -109,8 +120,18 @@ | |
417 | } | |
418 | ||
419 | /* | |
420 | - * Flush the input buffer | |
421 | + * n_tty_flush_buffer - clean input queue | |
422 | + * @tty: terminal device | |
423 | + * | |
424 | + * Flush the input buffer. Called when the line discipline is | |
425 | + * being closed, when the tty layer wants the buffer flushed (eg | |
426 | + * at hangup) or when the N_TTY line discipline internally has to | |
427 | + * clean the pending queue (for example some signals). | |
428 | + * | |
429 | + * FIXME: tty->ctrl_status is not spinlocked and relies on | |
430 | + * lock_kernel() still. | |
431 | */ | |
432 | + | |
433 | void n_tty_flush_buffer(struct tty_struct * tty) | |
434 | { | |
435 | /* clear everything and unthrottle the driver */ | |
436 | @@ -127,8 +148,13 @@ | |
437 | } | |
438 | ||
439 | /* | |
440 | - * Return number of characters buffered to be delivered to user | |
441 | + * n_tty_chars_in_buffer - report available bytes | |
442 | + * @tty: tty device | |
443 | + * | |
444 | + * Report the number of characters buffered to be delivered to user | |
445 | + * at this instant in time. | |
446 | */ | |
447 | + | |
448 | ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) | |
449 | { | |
450 | unsigned long flags; | |
451 | @@ -210,9 +236,19 @@ | |
452 | } | |
453 | ||
454 | /* | |
455 | - * opost_block --- to speed up block console writes, among other | |
456 | - * things. | |
457 | + * opost_block - block postprocess | |
458 | + * @tty: terminal device | |
459 | + * @inbuf: user buffer | |
460 | + * @nr: number of bytes | |
461 | + * | |
462 | + * This path is used to speed up block console writes, among other | |
463 | + * things when processing blocks of output data. It handles only | |
464 | + * the simple cases normally found and helps to generate blocks of | |
465 | + * symbols for the console driver and thus improve performance. | |
466 | + * | |
467 | + * Called from write_chan under the tty layer write lock. | |
468 | */ | |
469 | + | |
470 | static ssize_t opost_block(struct tty_struct * tty, | |
471 | const unsigned char * inbuf, unsigned int nr) | |
472 | { | |
473 | @@ -301,6 +337,16 @@ | |
474 | } | |
475 | } | |
476 | ||
477 | +/* | |
478 | + * eraser - handle erase function | |
479 | + * @c: character input | |
480 | + * @tty: terminal device | |
481 | + * | |
482 | + * Perform erase and neccessary output when an erase character is | |
483 | + * present in the stream from the driver layer. Handles the complexities | |
484 | + * of UTF-8 multibyte symbols. | |
485 | + */ | |
486 | + | |
487 | static void eraser(unsigned char c, struct tty_struct *tty) | |
488 | { | |
489 | enum { ERASE, WERASE, KILL } kill_type; | |
490 | @@ -417,6 +463,18 @@ | |
491 | finish_erasing(tty); | |
492 | } | |
493 | ||
494 | +/* | |
495 | + * isig - handle the ISIG optio | |
496 | + * @sig: signal | |
497 | + * @tty: terminal | |
498 | + * @flush: force flush | |
499 | + * | |
500 | + * Called when a signal is being sent due to terminal input. This | |
501 | + * may caus terminal flushing to take place according to the termios | |
502 | + * settings and character used. Called from the driver receive_buf | |
503 | + * path so serialized. | |
504 | + */ | |
505 | + | |
506 | static inline void isig(int sig, struct tty_struct *tty, int flush) | |
507 | { | |
508 | if (tty->pgrp > 0) | |
509 | @@ -428,6 +486,16 @@ | |
510 | } | |
511 | } | |
512 | ||
513 | +/* | |
514 | + * n_tty_receive_break - handle break | |
515 | + * @tty: terminal | |
516 | + * | |
517 | + * An RS232 break event has been hit in the incoming bitstream. This | |
518 | + * can cause a variety of events depending upon the termios settings. | |
519 | + * | |
520 | + * Called from the receive_buf path so single threaded. | |
521 | + */ | |
522 | + | |
523 | static inline void n_tty_receive_break(struct tty_struct *tty) | |
524 | { | |
525 | if (I_IGNBRK(tty)) | |
526 | @@ -445,19 +513,41 @@ | |
527 | wake_up_interruptible(&tty->poll_wait); | |
528 | } | |
529 | ||
530 | +/* | |
531 | + * n_tty_receive_overrun - handle overrun reporting | |
532 | + * @tty: terminal | |
533 | + * | |
534 | + * Data arrived faster than we could process it. While the tty | |
535 | + * driver has flagged this the bits that were missed are gone | |
536 | + * forever. | |
537 | + * | |
538 | + * Called from the receive_buf path so single threaded. Does not | |
539 | + * need locking as num_overrun and overrun_time are function | |
540 | + * private. | |
541 | + */ | |
542 | + | |
543 | static inline void n_tty_receive_overrun(struct tty_struct *tty) | |
544 | { | |
545 | char buf[64]; | |
546 | ||
547 | tty->num_overrun++; | |
548 | if (time_before(tty->overrun_time, jiffies - HZ)) { | |
549 | - printk("%s: %d input overrun(s)\n", tty_name(tty, buf), | |
550 | + printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf), | |
551 | tty->num_overrun); | |
552 | tty->overrun_time = jiffies; | |
553 | tty->num_overrun = 0; | |
554 | } | |
555 | } | |
556 | ||
557 | +/* | |
558 | + * n_tty_receive_parity_error - error notifier | |
559 | + * @tty: terminal device | |
560 | + * @c: character | |
561 | + * | |
562 | + * Process a parity error and queue the right data to indicate | |
563 | + * the error case if neccessary. Locking as per n_tty_receive_buf. | |
564 | + */ | |
565 | + | |
566 | static inline void n_tty_receive_parity_error(struct tty_struct *tty, | |
567 | unsigned char c) | |
568 | { | |
569 | @@ -476,6 +566,16 @@ | |
570 | wake_up_interruptible(&tty->poll_wait); | |
571 | } | |
572 | ||
573 | +/* | |
574 | + * n_tty_receive_char - perform processing | |
575 | + * @tty: terminal device | |
576 | + * @c: character | |
577 | + * | |
578 | + * Process an individual character of input received from the driver. | |
579 | + * This is serialized with respect to itself by the rules for the | |
580 | + * driver above. | |
581 | + */ | |
582 | + | |
583 | static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) | |
584 | { | |
585 | if (tty->raw) { | |
586 | @@ -667,6 +767,16 @@ | |
587 | put_tty_queue(c, tty); | |
588 | } | |
589 | ||
590 | +/* | |
591 | + * n_tty_receive_room - receive space | |
592 | + * @tty: terminal | |
593 | + * | |
594 | + * Called by the driver to find out how much data it is | |
595 | + * permitted to feed to the line discipline without any being lost | |
596 | + * and thus to manage flow control. Not serialized. Answers for the | |
597 | + * "instant". | |
598 | + */ | |
599 | + | |
600 | static int n_tty_receive_room(struct tty_struct *tty) | |
601 | { | |
602 | int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; | |
603 | @@ -685,6 +795,19 @@ | |
604 | return 0; | |
605 | } | |
606 | ||
607 | +/* | |
608 | + * n_tty_receive_buf - data receive | |
609 | + * @tty: terminal device | |
610 | + * @cp: buffer | |
611 | + * @fp: flag buffer | |
612 | + * @count: characters | |
613 | + * | |
614 | + * Called by the terminal driver when a block of characters has | |
615 | + * been received. This function must be called from soft contexts | |
616 | + * not from interrupt context. The driver is responsible for making | |
617 | + * calls one at a time and in order (or using queue_ldisc) | |
618 | + */ | |
619 | + | |
620 | static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, | |
621 | char *fp, int count) | |
622 | { | |
623 | @@ -770,6 +893,18 @@ | |
624 | current->sig->action[sig-1].sa.sa_handler == SIG_IGN); | |
625 | } | |
626 | ||
627 | +/* | |
628 | + * n_tty_set_termios - termios data changed | |
629 | + * @tty: terminal | |
630 | + * @old: previous data | |
631 | + * | |
632 | + * Called by the tty layer when the user changes termios flags so | |
633 | + * that the line discipline can plan ahead. This function cannot sleep | |
634 | + * and is protected from re-entry by the tty layer. The user is | |
635 | + * guaranteed that this function will not be re-entered or in progress | |
636 | + * when the ldisc is closed. | |
637 | + */ | |
638 | + | |
639 | static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) | |
640 | { | |
641 | if (!tty) | |
642 | @@ -785,7 +920,6 @@ | |
643 | I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || | |
644 | I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || | |
645 | I_PARMRK(tty)) { | |
646 | - cli(); | |
647 | memset(tty->process_char_map, 0, 256/8); | |
648 | ||
649 | if (I_IGNCR(tty) || I_ICRNL(tty)) | |
650 | @@ -821,7 +955,6 @@ | |
651 | set_bit(SUSP_CHAR(tty), &tty->process_char_map); | |
652 | } | |
653 | clear_bit(__DISABLED_CHAR, &tty->process_char_map); | |
654 | - sti(); | |
655 | tty->raw = 0; | |
656 | tty->real_raw = 0; | |
657 | } else { | |
658 | @@ -835,6 +968,16 @@ | |
659 | } | |
660 | } | |
661 | ||
662 | +/* | |
663 | + * n_tty_close - close the ldisc for this tty | |
664 | + * @tty: device | |
665 | + * | |
666 | + * Called from the terminal layer when this line discipline is | |
667 | + * being shut down, either because of a close or becsuse of a | |
668 | + * discipline change. The function will not be called while other | |
669 | + * ldisc methods are in progress. | |
670 | + */ | |
671 | + | |
672 | static void n_tty_close(struct tty_struct *tty) | |
673 | { | |
674 | n_tty_flush_buffer(tty); | |
675 | @@ -844,6 +987,16 @@ | |
676 | } | |
677 | } | |
678 | ||
679 | +/* | |
680 | + * n_tty_open - open an ldisc | |
681 | + * @tty: terminal to open | |
682 | + * | |
683 | + * Called when this line discipline is being attached to the | |
684 | + * terminal device. Can sleep. Called serialized so that no | |
685 | + * other events will occur in parallel. No further open will occur | |
686 | + * until a close. | |
687 | + */ | |
688 | + | |
689 | static int n_tty_open(struct tty_struct *tty) | |
690 | { | |
691 | if (!tty) | |
692 | @@ -876,13 +1029,22 @@ | |
693 | } | |
694 | ||
695 | /* | |
696 | - * Helper function to speed up read_chan. It is only called when | |
697 | + * copy_from_read_buf - copy read data directly | |
698 | + * @tty: terminal device | |
699 | + * @b: user data | |
700 | + * @nr: size of data | |
701 | + * | |
702 | + * Helper function to speed up read_chan. It is only called when | |
703 | * ICANON is off; it copies characters straight from the tty queue to | |
704 | - * user space directly. It can be profitably called twice; once to | |
705 | + * user space directly. It can be profitably called twice; once to | |
706 | * drain the space from the tail pointer to the (physical) end of the | |
707 | * buffer, and once to drain the space from the (physical) beginning of | |
708 | * the buffer to head pointer. | |
709 | + * | |
710 | + * Called under the tty->atomic_read sem and with TTY_DONT_FLIP set | |
711 | + * | |
712 | */ | |
713 | + | |
714 | static inline int copy_from_read_buf(struct tty_struct *tty, | |
715 | unsigned char **b, | |
716 | size_t *nr) | |
717 | @@ -910,25 +1072,18 @@ | |
718 | return retval; | |
719 | } | |
720 | ||
721 | -static ssize_t read_chan(struct tty_struct *tty, struct file *file, | |
722 | - unsigned char *buf, size_t nr) | |
723 | +/** | |
724 | + * job_control - check job control | |
725 | + * @tty: tty | |
726 | + * @file: file handle | |
727 | + * | |
728 | + * Perform job control management checks on this file/tty descriptor | |
729 | + * and if appropriate send any needed signals and return a negative | |
730 | + * error code if action should be taken. | |
731 | +*/ | |
732 | + | |
733 | +static int job_control(struct tty_struct *tty, struct file *file) | |
734 | { | |
735 | - unsigned char *b = buf; | |
736 | - struct wait_queue wait = { current, NULL }; | |
737 | - int c; | |
738 | - int minimum, time; | |
739 | - ssize_t retval = 0; | |
740 | - ssize_t size; | |
741 | - long timeout; | |
742 | - unsigned long flags; | |
743 | - | |
744 | -do_it_again: | |
745 | - | |
746 | - if (!tty->read_buf) { | |
747 | - printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); | |
748 | - return -EIO; | |
749 | - } | |
750 | - | |
751 | /* Job control check -- must be done at start and after | |
752 | every sleep (POSIX.1 7.1.1.4). */ | |
753 | /* NOTE: not yet done after every sleep pending a thorough | |
754 | @@ -947,7 +1102,48 @@ | |
755 | return -ERESTARTSYS; | |
756 | } | |
757 | } | |
758 | +return 0; | |
759 | + | |
760 | +} | |
761 | + | |
762 | +/** | |
763 | + * read_chan - read function for tty | |
764 | + * @tty: tty device | |
765 | + * @file: file object | |
766 | + * @buf: userspace buffer pointer | |
767 | + * @nr: size of I/O | |
768 | + * | |
769 | + * Perform reads for the line discipline. We are guaranteed that the | |
770 | + * line discipline will not be closed under us but we may get multiple | |
771 | + * parallel readers and must handle this ourselves. We may also get | |
772 | + * a hangup. Always called in user context, may sleep. | |
773 | + * | |
774 | + * This code must be sure never to sleep through a hangup. | |
775 | + */ | |
776 | + | |
777 | +static ssize_t read_chan(struct tty_struct *tty, struct file *file, | |
778 | + unsigned char *buf, size_t nr) | |
779 | +{ | |
780 | + unsigned char *b = buf; | |
781 | + DECLARE_WAITQUEUE(wait, current); | |
782 | + int c; | |
783 | + int minimum, time; | |
784 | + ssize_t retval = 0; | |
785 | + ssize_t size; | |
786 | + long timeout; | |
787 | + unsigned long flags; | |
788 | ||
789 | + do_it_again: | |
790 | + | |
791 | + if (!tty->read_buf) { | |
792 | + printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); | |
793 | + return -EIO; | |
794 | + } | |
795 | + | |
796 | + c = job_control(tty, file); | |
797 | + if(c < 0) | |
798 | + return c; | |
799 | + | |
800 | minimum = time = 0; | |
801 | timeout = MAX_SCHEDULE_TIMEOUT; | |
802 | if (!tty->icanon) { | |
803 | @@ -969,6 +1165,9 @@ | |
804 | } | |
805 | } | |
806 | ||
807 | + /* | |
808 | + * Internal serialization of reads. | |
809 | + */ | |
810 | if (file->f_flags & O_NONBLOCK) { | |
811 | if (down_trylock(&tty->atomic_read)) | |
812 | return -EAGAIN; | |
813 | @@ -1103,6 +1302,21 @@ | |
814 | return retval; | |
815 | } | |
816 | ||
817 | +/* | |
818 | + * write_chan - write function for tty | |
819 | + * @tty: tty device | |
820 | + * @file: file object | |
821 | + * @buf: userspace buffer pointer | |
822 | + * @nr: size of I/O | |
823 | + * | |
824 | + * Write function of the terminal device. This is serialized with | |
825 | + * respect to other write callers but not to termios changes, reads | |
826 | + * and other such events. We must be careful with N_TTY as the receive | |
827 | + * code will echo characters, thus calling driver write methods. | |
828 | + * | |
829 | + * This code must be sure never to sleep through a hangup. | |
830 | + */ | |
831 | + | |
832 | static ssize_t write_chan(struct tty_struct * tty, struct file * file, | |
833 | const unsigned char * buf, size_t nr) | |
834 | { | |
835 | @@ -1172,6 +1386,25 @@ | |
836 | return (b - buf) ? b - buf : retval; | |
837 | } | |
838 | ||
839 | +/* | |
840 | + * normal_poll - poll method for N_TTY | |
841 | + * @tty: terminal device | |
842 | + * @file: file accessing it | |
843 | + * @wait: poll table | |
844 | + * | |
845 | + * Called when the line discipline is asked to poll() for data or | |
846 | + * for special events. This code is not serialized with respect to | |
847 | + * other events save open/close. | |
848 | + * | |
849 | + * This code must be sure never to sleep through a hangup. | |
850 | + * Called without the kernel lock held - fine | |
851 | + * | |
852 | + * FIXME: if someone changes the VMIN or discipline settings for the | |
853 | + * terminal while another process is in poll() the poll does not | |
854 | + * recompute the new limits. Possibly set_termios should issue | |
855 | + * a read wakeup to fix this bug. | |
856 | + */ | |
857 | + | |
858 | static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait) | |
859 | { | |
860 | unsigned int mask = 0; | |
861 | diff -urN linux-2.2.26.orig/drivers/char/pcxx.c linux-2.2.26/drivers/char/pcxx.c | |
862 | --- linux-2.2.26.orig/drivers/char/pcxx.c 2001-03-25 18:31:25.000000000 +0200 | |
863 | +++ linux-2.2.26/drivers/char/pcxx.c 2004-10-31 09:34:16.000000000 +0100 | |
864 | @@ -621,10 +621,10 @@ | |
865 | ** please send me a note. brian@ilinx.com | |
866 | ** Don't know either what this is supposed to do clameter@waterf.org. | |
867 | */ | |
868 | - if(tty->ldisc.num != ldiscs[N_TTY].num) { | |
869 | + if(tty->ldisc.num != N_TTY) { | |
870 | if(tty->ldisc.close) | |
871 | (tty->ldisc.close)(tty); | |
872 | - tty->ldisc = ldiscs[N_TTY]; | |
873 | + tty->ldisc = *(tty_ldisc_get(N_TTY)); | |
874 | tty->termios->c_line = N_TTY; | |
875 | if(tty->ldisc.open) | |
876 | (tty->ldisc.open)(tty); | |
877 | diff -urN linux-2.2.26.orig/drivers/char/pty.c linux-2.2.26/drivers/char/pty.c | |
878 | --- linux-2.2.26.orig/drivers/char/pty.c 2001-03-25 18:31:24.000000000 +0200 | |
879 | +++ linux-2.2.26/drivers/char/pty.c 2004-10-31 09:17:13.000000000 +0100 | |
880 | @@ -134,6 +134,10 @@ | |
881 | * (2) avoid redundant copying for cases where count >> receive_room | |
882 | * N.B. Calls from user space may now return an error code instead of | |
883 | * a count. | |
884 | + * | |
885 | + * FIXME: Our pty_write method is called with our ldisc lock held but | |
886 | + * not our partners. We can't just take the other one blindly without | |
887 | + + * risking deadlocks. There is also the small matter of TTY_DONT_FLIP | |
888 | */ | |
889 | static int pty_write(struct tty_struct * tty, int from_user, | |
890 | const unsigned char *buf, int count) | |
891 | diff -urN linux-2.2.26.orig/drivers/char/riscom8.c linux-2.2.26/drivers/char/riscom8.c | |
892 | --- linux-2.2.26.orig/drivers/char/riscom8.c 2001-11-02 17:39:06.000000000 +0100 | |
893 | +++ linux-2.2.26/drivers/char/riscom8.c 2004-10-31 09:21:17.000000000 +0100 | |
894 | @@ -1110,7 +1110,8 @@ | |
895 | struct riscom_board *bp; | |
896 | unsigned long flags; | |
897 | unsigned long timeout; | |
898 | - | |
899 | + struct tty_ldisc *ld; | |
900 | + | |
901 | if (!port || rc_paranoia_check(port, tty->device, "close")) | |
902 | return; | |
903 | ||
904 | @@ -1180,6 +1181,12 @@ | |
905 | rc_shutdown_port(bp, port); | |
906 | if (tty->driver.flush_buffer) | |
907 | tty->driver.flush_buffer(tty); | |
908 | + ld = tty_ldisc_ref(tty); | |
909 | + if (ld != NULL) { | |
910 | + if(ld->flush_buffer) | |
911 | + ld->flush_buffer(tty); | |
912 | + tty_ldisc_deref(ld); | |
913 | + } | |
914 | if (tty->ldisc.flush_buffer) | |
915 | tty->ldisc.flush_buffer(tty); | |
916 | tty->closing = 0; | |
917 | @@ -1358,9 +1365,7 @@ | |
918 | ||
919 | wake_up_interruptible(&tty->write_wait); | |
920 | wake_up_interruptible(&tty->poll_wait); | |
921 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
922 | - tty->ldisc.write_wakeup) | |
923 | - (tty->ldisc.write_wakeup)(tty); | |
924 | + tty_wakeup(tty); | |
925 | } | |
926 | ||
927 | static int rc_get_modem_info(struct riscom_port * port, unsigned int *value) | |
928 | @@ -1736,9 +1741,7 @@ | |
929 | return; | |
930 | ||
931 | if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { | |
932 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
933 | - tty->ldisc.write_wakeup) | |
934 | - (tty->ldisc.write_wakeup)(tty); | |
935 | + tty_wakeup(tty); | |
936 | wake_up_interruptible(&tty->write_wait); | |
937 | wake_up_interruptible(&tty->poll_wait); | |
938 | } | |
939 | diff -urN linux-2.2.26.orig/drivers/char/selection.c linux-2.2.26/drivers/char/selection.c | |
940 | --- linux-2.2.26.orig/drivers/char/selection.c 2001-03-25 18:31:25.000000000 +0200 | |
941 | +++ linux-2.2.26/drivers/char/selection.c 2004-10-31 09:22:38.000000000 +0100 | |
942 | @@ -296,9 +296,11 @@ | |
943 | { | |
944 | struct vt_struct *vt = (struct vt_struct *) tty->driver_data; | |
945 | int pasted = 0, count; | |
946 | + struct tty_ldisc *ld; | |
947 | struct wait_queue wait = { current, NULL }; | |
948 | ||
949 | poke_blanked_console(); | |
950 | + ld = tty_ldisc_ref_wait(tty); | |
951 | add_wait_queue(&vt->paste_wait, &wait); | |
952 | while (sel_buffer && sel_buffer_lth > pasted) { | |
953 | current->state = TASK_INTERRUPTIBLE; | |
954 | @@ -313,6 +315,8 @@ | |
955 | } | |
956 | remove_wait_queue(&vt->paste_wait, &wait); | |
957 | current->state = TASK_RUNNING; | |
958 | + | |
959 | + tty_ldisc_deref(ld); | |
960 | return 0; | |
961 | } | |
962 | ||
963 | diff -urN linux-2.2.26.orig/drivers/char/serial167.c linux-2.2.26/drivers/char/serial167.c | |
964 | --- linux-2.2.26.orig/drivers/char/serial167.c 2001-03-25 18:31:26.000000000 +0200 | |
965 | +++ linux-2.2.26/drivers/char/serial167.c 2004-10-31 09:36:07.000000000 +0100 | |
966 | @@ -1943,10 +1943,10 @@ | |
967 | tty->ldisc.flush_buffer(tty); | |
968 | info->event = 0; | |
969 | info->tty = 0; | |
970 | - if (tty->ldisc.num != ldiscs[N_TTY].num) { | |
971 | + if (tty->ldisc.num != N_TTY) { | |
972 | if (tty->ldisc.close) | |
973 | (tty->ldisc.close)(tty); | |
974 | - tty->ldisc = ldiscs[N_TTY]; | |
975 | + tty->ldisc = *(tty_ldisc_get(N_TTY)); | |
976 | tty->termios->c_line = N_TTY; | |
977 | if (tty->ldisc.open) | |
978 | (tty->ldisc.open)(tty); | |
979 | diff -urN linux-2.2.26.orig/drivers/char/synclink.c linux-2.2.26/drivers/char/synclink.c | |
980 | --- linux-2.2.26.orig/drivers/char/synclink.c 2001-11-02 17:39:06.000000000 +0100 | |
981 | +++ linux-2.2.26/drivers/char/synclink.c 2004-10-31 09:30:48.000000000 +0100 | |
982 | @@ -990,6 +990,42 @@ | |
983 | return 0; | |
984 | } | |
985 | ||
986 | +/** | |
987 | + * line discipline callback wrappers | |
988 | + * | |
989 | + * The wrappers maintain line discipline references | |
990 | + * while calling into the line discipline. | |
991 | + * | |
992 | + * ldisc_flush_buffer - flush line discipline receive buffers | |
993 | + * ldisc_receive_buf - pass receive data to line discipline | |
994 | + */ | |
995 | + | |
996 | +static void ldisc_flush_buffer(struct tty_struct *tty) | |
997 | +{ | |
998 | + struct tty_ldisc *ld = tty_ldisc_ref(tty); | |
999 | + | |
1000 | + if (ld) { | |
1001 | + if (ld->flush_buffer) | |
1002 | + ld->flush_buffer(tty); | |
1003 | + tty_ldisc_deref(ld); | |
1004 | + } | |
1005 | +} | |
1006 | + | |
1007 | +static void ldisc_receive_buf(struct tty_struct *tty, | |
1008 | + const __u8 *data, char *flags, int count) | |
1009 | +{ | |
1010 | + struct tty_ldisc *ld; | |
1011 | + | |
1012 | + if (!tty) | |
1013 | + return; | |
1014 | + ld = tty_ldisc_ref(tty); | |
1015 | + if (ld) { | |
1016 | + if (ld->receive_buf) | |
1017 | + ld->receive_buf(tty, data, flags, count); | |
1018 | + tty_ldisc_deref(ld); | |
1019 | + } | |
1020 | +} | |
1021 | + | |
1022 | /* mgsl_stop() throttle (stop) transmitter | |
1023 | * | |
1024 | * Arguments: tty pointer to tty info structure | |
1025 | @@ -1141,13 +1177,7 @@ | |
1026 | __FILE__,__LINE__,info->device_name); | |
1027 | ||
1028 | if (tty) { | |
1029 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
1030 | - tty->ldisc.write_wakeup) { | |
1031 | - if ( debug_level >= DEBUG_LEVEL_BH ) | |
1032 | - printk( "%s(%d):calling ldisc.write_wakeup on %s\n", | |
1033 | - __FILE__,__LINE__,info->device_name); | |
1034 | - (tty->ldisc.write_wakeup)(tty); | |
1035 | - } | |
1036 | + tty_wakeup(tty); | |
1037 | wake_up_interruptible(&tty->write_wait); | |
1038 | } | |
1039 | ||
1040 | @@ -2392,11 +2422,8 @@ | |
1041 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | |
1042 | ||
1043 | wake_up_interruptible(&tty->write_wait); | |
1044 | - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | |
1045 | - tty->ldisc.write_wakeup) | |
1046 | - (tty->ldisc.write_wakeup)(tty); | |
1047 | - | |
1048 | -} /* end of mgsl_flush_buffer() */ | |
1049 | + tty_wakeup(tty); | |
1050 | +} | |
1051 | ||
1052 | /* mgsl_send_xchar() | |
1053 | * | |
1054 | @@ -3297,10 +3324,8 @@ | |
1055 | ||
1056 | if (tty->driver.flush_buffer) | |
1057 | tty->driver.flush_buffer(tty); | |
1058 | - | |
1059 | - if (tty->ldisc.flush_buffer) | |
1060 | - tty->ldisc.flush_buffer(tty); | |
1061 | - | |
1062 | + | |
1063 | + ldisc_flush_buffer(tty); | |
1064 | shutdown(info); | |
1065 | ||
1066 | tty->closing = 0; | |
1067 | @@ -6999,11 +7024,7 @@ | |
1068 | } | |
1069 | else | |
1070 | #endif | |
1071 | - { | |
1072 | - /* Call the line discipline receive callback directly. */ | |
1073 | - if ( tty && tty->ldisc.receive_buf ) | |
1074 | - tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); | |
1075 | - } | |
1076 | + ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); | |
1077 | } | |
1078 | } | |
1079 | /* Free the buffers used by this frame. */ | |
1080 | @@ -7175,9 +7196,7 @@ | |
1081 | memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize); | |
1082 | info->icount.rxok++; | |
1083 | ||
1084 | - /* Call the line discipline receive callback directly. */ | |
1085 | - if ( tty && tty->ldisc.receive_buf ) | |
1086 | - tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); | |
1087 | + ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); | |
1088 | } | |
1089 | ||
1090 | /* Free the buffers used by this frame. */ | |
1091 | diff -urN linux-2.2.26.orig/drivers/char/tty_io.c linux-2.2.26/drivers/char/tty_io.c | |
1092 | --- linux-2.2.26.orig/drivers/char/tty_io.c 2004-10-31 11:15:19.128606952 +0100 | |
1093 | +++ linux-2.2.26/drivers/char/tty_io.c 2004-10-31 12:02:45.000000000 +0100 | |
1094 | @@ -101,9 +101,13 @@ | |
1095 | #define TTY_PARANOIA_CHECK 1 | |
1096 | #define CHECK_TTY_COUNT 1 | |
1097 | ||
1098 | +#define __builtin_expect(x, expected_value) (x) | |
1099 | +#define likely(x) __builtin_expect((x),1) | |
1100 | + | |
1101 | +/* Lock for tty_termios changes - private to tty_io/tty_ioctl */ | |
1102 | +spinlock_t tty_termios_lock = SPIN_LOCK_UNLOCKED; | |
1103 | struct termios tty_std_termios; /* for the benefit of tty drivers */ | |
1104 | struct tty_driver *tty_drivers = NULL; /* linked list of tty drivers */ | |
1105 | -struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ | |
1106 | ||
1107 | #ifdef CONFIG_UNIX98_PTYS | |
1108 | extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */ | |
1109 | @@ -204,44 +208,256 @@ | |
1110 | return 0; | |
1111 | } | |
1112 | ||
1113 | +/* | |
1114 | + * This is probably overkill for real world processors but | |
1115 | + * they are not on hot paths so a little discipline won't do | |
1116 | + * any harm. | |
1117 | + */ | |
1118 | + | |
1119 | +static void tty_set_termios_ldisc(struct tty_struct *tty, int num) | |
1120 | +{ | |
1121 | + unsigned long flags; | |
1122 | + spin_lock_irqsave(&tty_termios_lock, flags); | |
1123 | + tty->termios->c_line = num; | |
1124 | + spin_unlock_irqrestore(&tty_termios_lock, flags); | |
1125 | +} | |
1126 | + | |
1127 | +/* | |
1128 | + * This guards the refcounted line discipline lists. The lock | |
1129 | + * must be taken with irqs off because there are hangup path | |
1130 | + * callers who will do ldisc lookups and cannot sleep. | |
1131 | + */ | |
1132 | + | |
1133 | +spinlock_t tty_ldisc_lock = SPIN_LOCK_UNLOCKED; | |
1134 | +DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); | |
1135 | +struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ | |
1136 | + | |
1137 | int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) | |
1138 | { | |
1139 | + | |
1140 | + unsigned long flags; | |
1141 | + int ret = 0; | |
1142 | + | |
1143 | if (disc < N_TTY || disc >= NR_LDISCS) | |
1144 | return -EINVAL; | |
1145 | - | |
1146 | + | |
1147 | + spin_lock_irqsave(&tty_ldisc_lock, flags); | |
1148 | if (new_ldisc) { | |
1149 | - ldiscs[disc] = *new_ldisc; | |
1150 | - ldiscs[disc].flags |= LDISC_FLAG_DEFINED; | |
1151 | - ldiscs[disc].num = disc; | |
1152 | - } else | |
1153 | - memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc)); | |
1154 | + tty_ldiscs[disc] = *new_ldisc; | |
1155 | + tty_ldiscs[disc].num = disc; | |
1156 | + tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; | |
1157 | + tty_ldiscs[disc].refcount = 0; | |
1158 | + } else { | |
1159 | + if(tty_ldiscs[disc].refcount) | |
1160 | + ret = -EBUSY; | |
1161 | + else | |
1162 | + tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; | |
1163 | + } | |
1164 | + spin_unlock_irqrestore(&tty_ldisc_lock, flags); | |
1165 | ||
1166 | - return 0; | |
1167 | + return ret; | |
1168 | } | |
1169 | ||
1170 | -/* Set the discipline of a tty line. */ | |
1171 | +EXPORT_SYMBOL(tty_register_ldisc); | |
1172 | + | |
1173 | +struct tty_ldisc *tty_ldisc_get(int disc) | |
1174 | +{ | |
1175 | + unsigned long flags; | |
1176 | + struct tty_ldisc *ld; | |
1177 | + | |
1178 | + if (disc < N_TTY || disc >= NR_LDISCS) | |
1179 | + return NULL; | |
1180 | + | |
1181 | + spin_lock_irqsave(&tty_ldisc_lock, flags); | |
1182 | + | |
1183 | + ld = &tty_ldiscs[disc]; | |
1184 | + /* Check the entry is defined */ | |
1185 | + if(ld->flags & LDISC_FLAG_DEFINED) | |
1186 | + ld->refcount++; | |
1187 | + else | |
1188 | + ld = NULL; | |
1189 | + spin_unlock_irqrestore(&tty_ldisc_lock, flags); | |
1190 | + return ld; | |
1191 | +} | |
1192 | + | |
1193 | +EXPORT_SYMBOL_GPL(tty_ldisc_get); | |
1194 | + | |
1195 | +void tty_ldisc_put(int disc) | |
1196 | +{ | |
1197 | + struct tty_ldisc *ld; | |
1198 | + unsigned long flags; | |
1199 | + | |
1200 | + if (disc < N_TTY || disc >= NR_LDISCS) | |
1201 | + BUG(); | |
1202 | + | |
1203 | + spin_lock_irqsave(&tty_ldisc_lock, flags); | |
1204 | + ld = &tty_ldiscs[disc]; | |
1205 | + if(ld->refcount <= 0) | |
1206 | + BUG(); | |
1207 | + ld->refcount--; | |
1208 | + spin_unlock_irqrestore(&tty_ldisc_lock, flags); | |
1209 | +} | |
1210 | + | |
1211 | +EXPORT_SYMBOL_GPL(tty_ldisc_put); | |
1212 | + | |
1213 | +void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) | |
1214 | +{ | |
1215 | + tty->ldisc = *ld; | |
1216 | + tty->ldisc.refcount = 0; | |
1217 | +} | |
1218 | + | |
1219 | +/** | |
1220 | + * tty_ldisc_try - internal helper | |
1221 | + * @tty: the tty | |
1222 | + * | |
1223 | + * Make a single attempt to grab and bump the refcount on | |
1224 | + * the tty ldisc. Return 0 on failure or 1 on success. This is | |
1225 | + * used to implement both the waiting and non waiting versions | |
1226 | + * of tty_ldisc_ref | |
1227 | + */ | |
1228 | + | |
1229 | +static int tty_ldisc_try(struct tty_struct *tty) | |
1230 | +{ | |
1231 | + unsigned long flags; | |
1232 | + struct tty_ldisc *ld; | |
1233 | + int ret = 0; | |
1234 | + | |
1235 | + spin_lock_irqsave(&tty_ldisc_lock, flags); | |
1236 | + ld = &tty->ldisc; | |
1237 | + if(test_bit(TTY_LDISC, &tty->flags)) { | |
1238 | + ld->refcount++; | |
1239 | + ret = 1; | |
1240 | + } | |
1241 | + spin_unlock_irqrestore(&tty_ldisc_lock, flags); | |
1242 | + return ret; | |
1243 | +} | |
1244 | + | |
1245 | +/** | |
1246 | + * tty_ldisc_ref_wait - wait for the tty ldisc | |
1247 | + * @tty: tty device | |
1248 | + * | |
1249 | + * Dereference the line discipline for the terminal and take a | |
1250 | + * reference to it. If the line discipline is in flux then | |
1251 | + * wait patiently until it changes. | |
1252 | + * | |
1253 | + * Note: Must not be called from an IRQ/timer context. The caller | |
1254 | + * must also be careful not to hold other locks that will deadlock | |
1255 | + * against a discipline change, such as an existing ldisc reference | |
1256 | + * (which we check for) | |
1257 | + */ | |
1258 | + | |
1259 | +struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) | |
1260 | +{ | |
1261 | + /* wait_event is a macro */ | |
1262 | + wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); | |
1263 | + return &tty->ldisc; | |
1264 | +} | |
1265 | + | |
1266 | +EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); | |
1267 | + | |
1268 | +/** | |
1269 | + * tty_ldisc_ref - get the tty ldisc | |
1270 | + * @tty: tty device | |
1271 | + * | |
1272 | + * Dereference the line discipline for the terminal and take a | |
1273 | + * reference to it. If the line discipline is in flux then | |
1274 | + * return NULL. Can be called from IRQ and timer functions. | |
1275 | + */ | |
1276 | + | |
1277 | +struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) | |
1278 | +{ | |
1279 | + if(tty_ldisc_try(tty)) | |
1280 | + return &tty->ldisc; | |
1281 | + return NULL; | |
1282 | +} | |
1283 | + | |
1284 | +EXPORT_SYMBOL_GPL(tty_ldisc_ref); | |
1285 | + | |
1286 | +void tty_ldisc_deref(struct tty_ldisc *ld) | |
1287 | +{ | |
1288 | + unsigned long flags; | |
1289 | + | |
1290 | + if(ld == NULL) | |
1291 | + BUG(); | |
1292 | + | |
1293 | + spin_lock_irqsave(&tty_ldisc_lock, flags); | |
1294 | + if(ld->refcount == 0) | |
1295 | + printk(KERN_EMERG "tty_ldisc_deref: no references.\n"); | |
1296 | + else | |
1297 | + ld->refcount--; | |
1298 | + if(ld->refcount == 0) | |
1299 | + wake_up(&tty_ldisc_wait); | |
1300 | + spin_unlock_irqrestore(&tty_ldisc_lock, flags); | |
1301 | +} | |
1302 | + | |
1303 | +EXPORT_SYMBOL_GPL(tty_ldisc_deref); | |
1304 | + | |
1305 | +/** | |
1306 | + * tty_set_ldisc - set line discipline | |
1307 | + * @tty: the terminal to set | |
1308 | + * @ldisc: the line discipline | |
1309 | + * | |
1310 | + * Set the discipline of a tty line. Must be called from a process | |
1311 | + * context. | |
1312 | + */ | |
1313 | + | |
1314 | static int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |
1315 | { | |
1316 | int retval = 0; | |
1317 | struct tty_ldisc o_ldisc; | |
1318 | char buf[64]; | |
1319 | + int work; | |
1320 | + unsigned long flags; | |
1321 | + struct tty_ldisc *ld; | |
1322 | ||
1323 | if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) | |
1324 | return -EINVAL; | |
1325 | + | |
1326 | + restart: | |
1327 | + | |
1328 | + if (tty->ldisc.num == ldisc) | |
1329 | + return 0; /* We are already in the desired discipline */ | |
1330 | + | |
1331 | + ld = tty_ldisc_get(ldisc); | |
1332 | /* Eduardo Blanco <ejbs@cs.cs.com.uy> */ | |
1333 | /* Cyrus Durgin <cider@speakeasy.org> */ | |
1334 | - if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) { | |
1335 | + if (ld == NULL) { | |
1336 | char modname [20]; | |
1337 | sprintf(modname, "tty-ldisc-%d", ldisc); | |
1338 | request_module (modname); | |
1339 | - } | |
1340 | - if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) | |
1341 | + ld = tty_ldisc_get(ldisc); } | |
1342 | + if (ld == NULL) | |
1343 | return -EINVAL; | |
1344 | ||
1345 | - if (tty->ldisc.num == ldisc) | |
1346 | - return 0; /* We are already in the desired discipline */ | |
1347 | - o_ldisc = tty->ldisc; | |
1348 | + /* | |
1349 | + * Make sure we don't change while someone holds a | |
1350 | + * reference to the line discipline. The TTY_LDISC bit | |
1351 | + * prevents anyone taking a reference once it is clear. | |
1352 | + * We need the lock to avoid racing reference takers. | |
1353 | + */ | |
1354 | + | |
1355 | + spin_lock_irqsave(&tty_ldisc_lock, flags); | |
1356 | + if(tty->ldisc.refcount) | |
1357 | + { | |
1358 | + /* Free the new ldisc we grabbed. Must drop the lock | |
1359 | + first. */ | |
1360 | + spin_unlock_irqrestore(&tty_ldisc_lock, flags); | |
1361 | + tty_ldisc_put(ldisc); | |
1362 | + if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) | |
1363 | + return -ERESTARTSYS; | |
1364 | + goto restart; | |
1365 | + } | |
1366 | + clear_bit(TTY_LDISC, &tty->flags); | |
1367 | + clear_bit(TTY_DONT_FLIP, &tty->flags); | |
1368 | + spin_unlock_irqrestore(&tty_ldisc_lock, flags); | |
1369 | + | |
1370 | + /* | |
1371 | + * From this point on we know nobody has an ldisc | |
1372 | + * usage reference, nor can they obtain one until | |
1373 | + * we say so later on. | |
1374 | + */ | |
1375 | ||
1376 | + o_ldisc = tty->ldisc; | |
1377 | tty_wait_until_sent(tty, 0); | |
1378 | ||
1379 | /* Shutdown the current discipline. */ | |
1380 | @@ -249,16 +465,20 @@ | |
1381 | (tty->ldisc.close)(tty); | |
1382 | ||
1383 | /* Now set up the new line discipline. */ | |
1384 | - tty->ldisc = ldiscs[ldisc]; | |
1385 | - tty->termios->c_line = ldisc; | |
1386 | + tty_ldisc_assign(tty, ld); | |
1387 | + tty_set_termios_ldisc(tty, ldisc); | |
1388 | if (tty->ldisc.open) | |
1389 | retval = (tty->ldisc.open)(tty); | |
1390 | if (retval < 0) { | |
1391 | - tty->ldisc = o_ldisc; | |
1392 | - tty->termios->c_line = tty->ldisc.num; | |
1393 | + tty_ldisc_put(ldisc); | |
1394 | + /* There is an outstanding reference here so this is safe */ | |
1395 | + tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num)); | |
1396 | + tty_set_termios_ldisc(tty, tty->ldisc.num); | |
1397 | if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) { | |
1398 | - tty->ldisc = ldiscs[N_TTY]; | |
1399 | - tty->termios->c_line = N_TTY; | |
1400 | + tty_ldisc_put(o_ldisc.num); | |
1401 | + /* This driver is always present */ | |
1402 | + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); | |
1403 | + tty_set_termios_ldisc(tty, N_TTY); | |
1404 | if (tty->ldisc.open) { | |
1405 | int r = tty->ldisc.open(tty); | |
1406 | ||
1407 | @@ -269,8 +489,23 @@ | |
1408 | } | |
1409 | } | |
1410 | } | |
1411 | + /* At this point we hold a reference to the new ldisc and a | |
1412 | + reference to the old ldisc. If we ended up flipping back | |
1413 | + to the existing ldisc we have two references to it */ | |
1414 | + | |
1415 | if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc) | |
1416 | tty->driver.set_ldisc(tty); | |
1417 | + | |
1418 | + tty_ldisc_put(o_ldisc.num); | |
1419 | + | |
1420 | + /* | |
1421 | + * Allow ldisc referencing to occur as soon as the driver | |
1422 | + * ldisc callback completes. | |
1423 | + */ | |
1424 | + | |
1425 | + set_bit(TTY_LDISC, &tty->flags); | |
1426 | + wake_up(&tty_ldisc_wait); | |
1427 | + | |
1428 | return retval; | |
1429 | } | |
1430 | ||
1431 | @@ -385,6 +620,25 @@ | |
1432 | }; | |
1433 | ||
1434 | /* | |
1435 | + * Internal and external helper for wakeups of tty | |
1436 | + */ | |
1437 | + | |
1438 | +void tty_wakeup(struct tty_struct *tty) | |
1439 | +{ | |
1440 | + struct tty_ldisc *ld; | |
1441 | + | |
1442 | + if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { | |
1443 | + ld = tty_ldisc_ref(tty); | |
1444 | + if(ld) { | |
1445 | + if(ld->write_wakeup) | |
1446 | + ld->write_wakeup(tty); | |
1447 | + tty_ldisc_deref(ld); | |
1448 | + } | |
1449 | + } | |
1450 | +} | |
1451 | + | |
1452 | +EXPORT_SYMBOL_GPL(tty_wakeup); | |
1453 | +/* | |
1454 | * This can be called through the "tq_scheduler" | |
1455 | * task-list. That is process synchronous, but | |
1456 | * doesn't hold any locks, so we need to make | |
1457 | @@ -397,6 +651,7 @@ | |
1458 | struct file * filp; | |
1459 | struct file * cons_filp = NULL; | |
1460 | struct task_struct *p; | |
1461 | + struct tty_ldisc *ld; | |
1462 | int closecount = 0, n; | |
1463 | ||
1464 | if (!tty) | |
1465 | @@ -426,19 +681,18 @@ | |
1466 | } | |
1467 | ||
1468 | /* FIXME! What are the locking issues here? This may me overdoing things.. */ | |
1469 | - { | |
1470 | - unsigned long flags; | |
1471 | - | |
1472 | - save_flags(flags); cli(); | |
1473 | - if (tty->ldisc.flush_buffer) | |
1474 | - tty->ldisc.flush_buffer(tty); | |
1475 | + ld = tty_ldisc_ref(tty); | |
1476 | + if(ld != NULL) | |
1477 | + { | |
1478 | + if (ld->flush_buffer) | |
1479 | + ld->flush_buffer(tty); | |
1480 | if (tty->driver.flush_buffer) | |
1481 | tty->driver.flush_buffer(tty); | |
1482 | - if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && | |
1483 | - tty->ldisc.write_wakeup) | |
1484 | - (tty->ldisc.write_wakeup)(tty); | |
1485 | - restore_flags(flags); | |
1486 | - } | |
1487 | + if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && ld->write_wakeup) | |
1488 | + ld->write_wakeup(tty); | |
1489 | + //if (ld->hangup) | |
1490 | + // ld->hangup(tty); | |
1491 | + } | |
1492 | ||
1493 | wake_up_interruptible(&tty->write_wait); | |
1494 | wake_up_interruptible(&tty->read_wait); | |
1495 | @@ -448,20 +702,17 @@ | |
1496 | * Shutdown the current line discipline, and reset it to | |
1497 | * N_TTY. | |
1498 | */ | |
1499 | + | |
1500 | if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) | |
1501 | + { | |
1502 | + unsigned long flags; | |
1503 | + spin_lock_irqsave(&tty_termios_lock, flags); | |
1504 | *tty->termios = tty->driver.init_termios; | |
1505 | - if (tty->ldisc.num != ldiscs[N_TTY].num) { | |
1506 | - if (tty->ldisc.close) | |
1507 | - (tty->ldisc.close)(tty); | |
1508 | - tty->ldisc = ldiscs[N_TTY]; | |
1509 | - tty->termios->c_line = N_TTY; | |
1510 | - if (tty->ldisc.open) { | |
1511 | - int i = (tty->ldisc.open)(tty); | |
1512 | - if (i < 0) | |
1513 | - printk("do_tty_hangup: N_TTY open: error %d\n", | |
1514 | - -i); | |
1515 | - } | |
1516 | + spin_unlock_irqrestore(&tty_termios_lock, flags); | |
1517 | } | |
1518 | + | |
1519 | + /* Defer ldisc switch */ | |
1520 | + /* tty_deferred_ldisc_switch(N_TTY); */ | |
1521 | ||
1522 | read_lock(&tasklist_lock); | |
1523 | for_each_task(p) { | |
1524 | @@ -493,6 +744,15 @@ | |
1525 | tty->driver.close(tty, cons_filp); | |
1526 | } else if (tty->driver.hangup) | |
1527 | (tty->driver.hangup)(tty); | |
1528 | + | |
1529 | + /* We don't want to have driver/ldisc interactions beyond | |
1530 | + the ones we did here. The driver layer expects no | |
1531 | + calls after ->hangup() from the ldisc side. However we | |
1532 | + can't yet guarantee all that */ | |
1533 | + | |
1534 | + set_bit(TTY_HUPPED, &tty->flags); | |
1535 | + if(ld) | |
1536 | + tty_ldisc_deref(ld); | |
1537 | unlock_kernel(); | |
1538 | } | |
1539 | ||
1540 | @@ -602,9 +862,8 @@ | |
1541 | } | |
1542 | if (tty->driver.start) | |
1543 | (tty->driver.start)(tty); | |
1544 | - if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && | |
1545 | - tty->ldisc.write_wakeup) | |
1546 | - (tty->ldisc.write_wakeup)(tty); | |
1547 | + /* If we have a running line discipline it may need kicking */ | |
1548 | + tty_wakeup(tty); | |
1549 | wake_up_interruptible(&tty->write_wait); | |
1550 | wake_up_interruptible(&tty->poll_wait); | |
1551 | } | |
1552 | @@ -615,6 +874,7 @@ | |
1553 | int i; | |
1554 | struct tty_struct * tty; | |
1555 | struct inode *inode; | |
1556 | + struct tty_ldisc *ld; | |
1557 | ||
1558 | /* Can't seek (pread) on ttys. */ | |
1559 | if (ppos != &file->f_pos) | |
1560 | @@ -643,10 +903,16 @@ | |
1561 | return -ERESTARTSYS; | |
1562 | } | |
1563 | #endif | |
1564 | - if (tty->ldisc.read) | |
1565 | - i = (tty->ldisc.read)(tty,file,buf,count); | |
1566 | + /* We want to wait for the line discipline to sort out in this | |
1567 | + situation */ | |
1568 | + ld = tty_ldisc_ref_wait(tty); | |
1569 | + lock_kernel(); | |
1570 | + if (ld->read) | |
1571 | + i = (ld->read)(tty,file,buf,count); | |
1572 | else | |
1573 | i = -EIO; | |
1574 | + tty_ldisc_deref(ld); | |
1575 | + unlock_kernel(); | |
1576 | if (i > 0) | |
1577 | inode->i_atime = CURRENT_TIME; | |
1578 | return i; | |
1579 | @@ -717,7 +983,9 @@ | |
1580 | int is_console; | |
1581 | struct tty_struct * tty; | |
1582 | struct inode *inode; | |
1583 | - | |
1584 | + ssize_t ret; | |
1585 | + struct tty_ldisc *ld; | |
1586 | + | |
1587 | /* Can't seek (pwrite) on ttys. */ | |
1588 | if (ppos != &file->f_pos) | |
1589 | return -ESPIPE; | |
1590 | @@ -749,10 +1017,15 @@ | |
1591 | } | |
1592 | } | |
1593 | #endif | |
1594 | - if (!tty->ldisc.write) | |
1595 | - return -EIO; | |
1596 | - return do_tty_write(tty->ldisc.write, tty, file, | |
1597 | - (const unsigned char *)buf, count); | |
1598 | + | |
1599 | + ld = tty_ldisc_ref_wait(tty); | |
1600 | + if (!ld->write) | |
1601 | + ret = -EIO; | |
1602 | + else | |
1603 | + ret = do_tty_write(ld->write, tty, file, | |
1604 | + (const unsigned char *) buf, count); | |
1605 | + tty_ldisc_deref(ld); | |
1606 | + return ret; | |
1607 | } | |
1608 | ||
1609 | /* Semaphore to protect creating and releasing a tty */ | |
2cf5f602 KT |
1610 | @@ -917,7 +1190,9 @@ |
1611 | (tty->ldisc.close)(tty); | |
1612 | goto release_mem_out; | |
1613 | } | |
1614 | - } | |
1615 | + set_bit(TTY_LDISC, &o_tty->flags); | |
1616 | + } | |
1617 | + set_bit(TTY_LDISC, &tty->flags); | |
1618 | goto success; | |
1619 | ||
1620 | /* | |
1621 | @@ -945,7 +1220,9 @@ | |
1622 | } | |
1623 | tty->count++; | |
1624 | tty->driver = *driver; /* N.B. why do this every time?? */ | |
1625 | - | |
1626 | + /* FIXME */ | |
1627 | + if(!test_bit(TTY_LDISC, &tty->flags)) | |
1628 | + printk(KERN_ERR "init_dev but no ldisc\n"); | |
1629 | success: | |
1630 | *ret_tty = tty; | |
1631 | ||
1632 | @@ -1023,6 +1300,7 @@ | |
1633 | int pty_master, tty_closing, o_tty_closing, do_sleep; | |
1634 | int idx; | |
1635 | char buf[64]; | |
1636 | + unsigned long flags; | |
1637 | ||
1638 | tty = (struct tty_struct *)filp->private_data; | |
1639 | if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev")) | |
1640 | @@ -1225,17 +1503,51 @@ | |
1641 | #endif | |
1642 | ||
1643 | /* | |
1644 | + * Prevent flush_to_ldisc() from rescheduling the work for later. Then | |
1645 | + * kill any delayed work. As this is the final close it does not | |
1646 | + * race with the set_ldisc code path. | |
1647 | + */ | |
1648 | + clear_bit(TTY_LDISC, &tty->flags); | |
1649 | + clear_bit(TTY_DONT_FLIP, &tty->flags); | |
1650 | + | |
1651 | + /* | |
1652 | + * Wait for any short term users (we know they are just driver | |
1653 | + * side waiters as the file is closing so user count on the file | |
1654 | + * side is zero. | |
1655 | + */ | |
1656 | + | |
1657 | + spin_lock_irqsave(&tty_ldisc_lock, flags); | |
1658 | + while(tty->ldisc.refcount) | |
1659 | + { | |
1660 | + spin_unlock_irqrestore(&tty_ldisc_lock, flags); | |
1661 | + wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); | |
1662 | + spin_lock_irqsave(&tty_ldisc_lock, flags); | |
1663 | + } | |
1664 | + spin_unlock_irqrestore(&tty_ldisc_lock, flags); | |
1665 | + | |
1666 | + /* | |
1667 | * Shutdown the current line discipline, and reset it to N_TTY. | |
1668 | * N.B. why reset ldisc when we're releasing the memory?? | |
1669 | + * FIXME: this MUST get fixed for the new reflocking | |
1670 | */ | |
1671 | if (tty->ldisc.close) | |
1672 | (tty->ldisc.close)(tty); | |
1673 | - tty->ldisc = ldiscs[N_TTY]; | |
1674 | - tty->termios->c_line = N_TTY; | |
1675 | + tty_ldisc_put(tty->ldisc.num); | |
1676 | + | |
1677 | + /* | |
1678 | + * Switch the line discipline back | |
1679 | + */ | |
1680 | + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); | |
1681 | + tty_set_termios_ldisc(tty,N_TTY); | |
1682 | + | |
1683 | if (o_tty) { | |
1684 | + /* FIXME: could o_tty be in setldisc here ? */ | |
1685 | + clear_bit(TTY_LDISC, &o_tty->flags); | |
1686 | if (o_tty->ldisc.close) | |
1687 | (o_tty->ldisc.close)(o_tty); | |
1688 | - o_tty->ldisc = ldiscs[N_TTY]; | |
1689 | + tty_ldisc_put(o_tty->ldisc.num); | |
1690 | + tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY)); | |
1691 | + tty_set_termios_ldisc(o_tty,N_TTY); | |
1692 | } | |
1693 | ||
1694 | /* | |
1695 | @@ -1409,14 +1721,18 @@ | |
1696 | static unsigned int tty_poll(struct file * filp, poll_table * wait) | |
1697 | { | |
1698 | struct tty_struct * tty; | |
1699 | + struct tty_ldisc *ld; | |
1700 | + int ret = 0; | |
1701 | ||
1702 | tty = (struct tty_struct *)filp->private_data; | |
1703 | if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_poll")) | |
1704 | return 0; | |
1705 | ||
1706 | - if (tty->ldisc.poll) | |
1707 | - return (tty->ldisc.poll)(tty, filp, wait); | |
1708 | - return 0; | |
1709 | + ld = tty_ldisc_ref_wait(tty); | |
1710 | + if (ld->poll) | |
1711 | + ret = (ld->poll)(tty, filp, wait); | |
1712 | + tty_ldisc_deref(ld); | |
1713 | + return ret; | |
1714 | } | |
1715 | ||
1716 | /* | |
1717 | @@ -1493,12 +1809,15 @@ | |
1718 | static int tiocsti(struct tty_struct *tty, char * arg) | |
1719 | { | |
1720 | char ch, mbz = 0; | |
1721 | + struct tty_ldisc *ld; | |
1722 | ||
1723 | if ((current->tty != tty) && !suser()) | |
1724 | return -EPERM; | |
1725 | if (get_user(ch, arg)) | |
1726 | return -EFAULT; | |
1727 | - tty->ldisc.receive_buf(tty, &ch, &mbz, 1); | |
1728 | + ld = tty_ldisc_ref_wait(tty); | |
1729 | + ld->receive_buf(tty, &ch, &mbz, 1); | |
1730 | + tty_ldisc_deref(ld); | |
1731 | return 0; | |
1732 | } | |
1733 | ||
1734 | @@ -1679,6 +1998,7 @@ | |
1735 | { | |
1736 | struct tty_struct *tty, *real_tty; | |
1737 | int retval; | |
1738 | + struct tty_ldisc *ld; | |
1739 | ||
1740 | tty = (struct tty_struct *)file->private_data; | |
1741 | if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl")) | |
1742 | @@ -1766,6 +2086,7 @@ | |
1743 | case TIOCGSID: | |
1744 | return tiocgsid(tty, real_tty, (pid_t *) arg); | |
1745 | case TIOCGETD: | |
1746 | + /* FIXME: check this is ok */ | |
1747 | return put_user(tty->ldisc.num, (int *) arg); | |
1748 | case TIOCSETD: | |
1749 | return tiocsetd(tty, (int *) arg); | |
1750 | @@ -1799,16 +2120,20 @@ | |
1751 | return send_break(tty, arg ? arg*(HZ/10) : HZ/4); | |
1752 | } | |
1753 | if (tty->driver.ioctl) { | |
1754 | - int retval = (tty->driver.ioctl)(tty, file, cmd, arg); | |
1755 | + retval = (tty->driver.ioctl)(tty, file, cmd, arg); | |
1756 | if (retval != -ENOIOCTLCMD) | |
1757 | return retval; | |
1758 | } | |
1759 | - if (tty->ldisc.ioctl) { | |
1760 | - int retval = (tty->ldisc.ioctl)(tty, file, cmd, arg); | |
1761 | - if (retval != -ENOIOCTLCMD) | |
1762 | - return retval; | |
1763 | + ld = tty_ldisc_ref_wait(tty); | |
1764 | + retval = -EINVAL; | |
1765 | + if (ld->ioctl) { | |
1766 | + if(likely(test_bit(TTY_LDISC, &tty->flags))) | |
1767 | + retval = ld->ioctl(tty, file, cmd, arg); | |
1768 | + if (retval == -ENOIOCTLCMD) | |
1769 | + retval = -EINVAL; | |
1770 | } | |
1771 | - return -EINVAL; | |
1772 | + tty_ldisc_deref(ld); | |
1773 | + return retval; | |
1774 | } | |
1775 | ||
1776 | ||
1777 | @@ -1833,14 +2158,20 @@ | |
1778 | int session; | |
1779 | int i; | |
1780 | struct file *filp; | |
1781 | + struct tty_ldisc *disc; | |
1782 | ||
1783 | if (!tty) | |
1784 | return; | |
1785 | session = tty->session; | |
1786 | - if (tty->ldisc.flush_buffer) | |
1787 | - tty->ldisc.flush_buffer(tty); | |
1788 | + /* We don't want an ldisc switch during this */ | |
1789 | + disc = tty_ldisc_ref(tty); | |
1790 | + if (disc && disc->flush_buffer) | |
1791 | + disc->flush_buffer(tty); | |
1792 | + tty_ldisc_deref(disc); | |
1793 | + | |
1794 | if (tty->driver.flush_buffer) | |
1795 | tty->driver.flush_buffer(tty); | |
1796 | + | |
1797 | read_lock(&tasklist_lock); | |
1798 | for_each_task(p) { | |
1799 | if ((p->tty == tty) || | |
1800 | @@ -1872,10 +2203,15 @@ | |
1801 | char *fp; | |
1802 | int count; | |
1803 | unsigned long flags; | |
1804 | + struct tty_ldisc *disc; | |
1805 | + | |
1806 | + disc = tty_ldisc_ref(tty); | |
1807 | + if (disc == NULL) /* !TTY_LDISC */ | |
1808 | + return; | |
1809 | ||
1810 | if (test_bit(TTY_DONT_FLIP, &tty->flags)) { | |
1811 | queue_task(&tty->flip.tqueue, &tq_timer); | |
1812 | - return; | |
1813 | + goto out; | |
1814 | } | |
1815 | if (tty->flip.buf_num) { | |
1816 | cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; | |
1817 | @@ -1897,8 +2233,31 @@ | |
1818 | count = tty->flip.count; | |
1819 | tty->flip.count = 0; | |
1820 | restore_flags(flags); | |
1821 | - | |
1822 | - tty->ldisc.receive_buf(tty, cp, fp, count); | |
1823 | + disc->receive_buf(tty, cp, fp, count); | |
1824 | + out: | |
1825 | + tty_ldisc_deref(disc); | |
1826 | +} | |
1827 | + | |
1828 | +/* | |
1829 | + * Call the ldisc flush directly from a driver. This function may | |
1830 | + * return an error and need retrying by the user. | |
1831 | + */ | |
1832 | + | |
1833 | +int tty_push_data(struct tty_struct *tty, unsigned char *cp, unsigned char *fp, int count) | |
1834 | +{ | |
1835 | + int ret = 0; | |
1836 | + struct tty_ldisc *disc; | |
1837 | + | |
1838 | + disc = tty_ldisc_ref(tty); | |
1839 | + if(test_bit(TTY_DONT_FLIP, &tty->flags)) | |
1840 | + ret = -EAGAIN; | |
1841 | + else if(disc == NULL) | |
1842 | + ret = -EIO; | |
1843 | + else | |
1844 | + disc->receive_buf(tty, cp, fp, count); | |
1845 | + tty_ldisc_deref(disc); | |
1846 | + return ret; | |
1847 | + | |
1848 | } | |
1849 | ||
1850 | /* | |
1851 | @@ -1960,7 +2319,7 @@ | |
1852 | { | |
1853 | memset(tty, 0, sizeof(struct tty_struct)); | |
1854 | tty->magic = TTY_MAGIC; | |
1855 | - tty->ldisc = ldiscs[N_TTY]; | |
1856 | + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); | |
1857 | tty->pgrp = -1; | |
1858 | tty->flip.char_buf_ptr = tty->flip.char_buf; | |
1859 | tty->flip.flag_buf_ptr = tty->flip.flag_buf; | |
1860 | @@ -2080,7 +2439,7 @@ | |
1861 | long __init console_init(long kmem_start, long kmem_end) | |
1862 | { | |
1863 | /* Setup the default TTY line discipline. */ | |
1864 | - memset(ldiscs, 0, sizeof(ldiscs)); | |
1865 | + memset(tty_ldiscs, 0, NR_LDISCS*sizeof(struct tty_ldisc)); | |
1866 | (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); | |
1867 | ||
1868 | /* | |
1869 | diff -urN linux-2.2.26.orig/drivers/char/tty_ioctl.c linux-2.2.26/drivers/char/tty_ioctl.c | |
1870 | --- linux-2.2.26.orig/drivers/char/tty_ioctl.c 2001-03-25 18:31:24.000000000 +0200 | |
1871 | +++ linux-2.2.26/drivers/char/tty_ioctl.c 2004-10-31 12:06:32.000000000 +0100 | |
1872 | @@ -33,6 +33,8 @@ | |
1873 | # define PRINTK(x) /**/ | |
1874 | #endif | |
1875 | ||
1876 | +extern spinlock_t tty_termios_lock; | |
1877 | + | |
1878 | /* | |
1879 | * Internal flag options for termios setting behavior | |
1880 | */ | |
1881 | @@ -100,8 +102,17 @@ | |
1882 | { | |
1883 | int canon_change; | |
1884 | struct termios old_termios = *tty->termios; | |
1885 | + struct tty_ldisc *ld; | |
1886 | + unsigned long flags; | |
1887 | + | |
1888 | + /* | |
1889 | + * Perform the actual termios internal changes under lock. | |
1890 | + */ | |
1891 | + | |
1892 | + /* FIXME: we need to decide on some locking/ordering semantics | |
1893 | + for the set_termios notification eventually */ | |
1894 | + spin_lock_irqsave(&tty_termios_lock, flags); | |
1895 | ||
1896 | - cli(); | |
1897 | *tty->termios = *new_termios; | |
1898 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); | |
1899 | canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; | |
1900 | @@ -111,7 +122,7 @@ | |
1901 | tty->canon_data = 0; | |
1902 | tty->erasing = 0; | |
1903 | } | |
1904 | - sti(); | |
1905 | + | |
1906 | if (canon_change && !L_ICANON(tty) && tty->read_cnt) | |
1907 | { | |
1908 | /* Get characters left over from canonical mode. */ | |
1909 | @@ -142,16 +153,21 @@ | |
1910 | if (tty->driver.set_termios) | |
1911 | (*tty->driver.set_termios)(tty, &old_termios); | |
1912 | ||
1913 | - if (tty->ldisc.set_termios) | |
1914 | - (*tty->ldisc.set_termios)(tty, &old_termios); | |
1915 | + ld = tty_ldisc_ref(tty); | |
1916 | + if (ld != NULL) { | |
1917 | + if (ld->set_termios) | |
1918 | + (ld->set_termios)(tty, &old_termios); | |
1919 | + tty_ldisc_deref(ld); | |
1920 | + } | |
1921 | + spin_unlock_irqrestore(&tty_termios_lock, flags); | |
1922 | } | |
1923 | ||
1924 | static int set_termios(struct tty_struct * tty, unsigned long arg, int opt) | |
1925 | { | |
1926 | struct termios tmp_termios; | |
1927 | - int retval; | |
1928 | + struct tty_ldisc *ld; | |
1929 | + int retval = tty_check_change(tty); | |
1930 | ||
1931 | - retval = tty_check_change(tty); | |
1932 | if (retval) | |
1933 | return retval; | |
1934 | ||
1935 | @@ -164,9 +180,13 @@ | |
1936 | return -EFAULT; | |
1937 | } | |
1938 | ||
1939 | - if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer) | |
1940 | - tty->ldisc.flush_buffer(tty); | |
1941 | + ld = tty_ldisc_ref(tty); | |
1942 | ||
1943 | + if (ld != NULL) { | |
1944 | + if ((opt & TERMIOS_FLUSH) && ld->flush_buffer) | |
1945 | + ld->flush_buffer(tty); | |
1946 | + tty_ldisc_deref(ld); | |
1947 | + } | |
1948 | if (opt & TERMIOS_WAIT) { | |
1949 | tty_wait_until_sent(tty, 0); | |
1950 | if (signal_pending(current)) | |
1951 | @@ -230,12 +250,16 @@ | |
1952 | static int get_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb) | |
1953 | { | |
1954 | struct sgttyb tmp; | |
1955 | + unsigned long flags; | |
1956 | ||
1957 | + spin_lock_irqsave(&tty_termios_lock, flags); | |
1958 | tmp.sg_ispeed = 0; | |
1959 | tmp.sg_ospeed = 0; | |
1960 | tmp.sg_erase = tty->termios->c_cc[VERASE]; | |
1961 | tmp.sg_kill = tty->termios->c_cc[VKILL]; | |
1962 | tmp.sg_flags = get_sgflags(tty); | |
1963 | + spin_unlock_irqrestore(&tty_termios_lock, flags); | |
1964 | + | |
1965 | if (copy_to_user(sgttyb, &tmp, sizeof(tmp))) | |
1966 | return -EFAULT; | |
1967 | return 0; | |
1968 | @@ -275,12 +299,15 @@ | |
1969 | retval = tty_check_change(tty); | |
1970 | if (retval) | |
1971 | return retval; | |
1972 | - termios = *tty->termios; | |
1973 | + | |
1974 | if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) | |
1975 | return -EFAULT; | |
1976 | + spin_lock_irqsave(&tty_termios_lock, flags); | |
1977 | + termios = *tty->termios; | |
1978 | termios.c_cc[VERASE] = tmp.sg_erase; | |
1979 | termios.c_cc[VKILL] = tmp.sg_kill; | |
1980 | set_sgflags(&termios, tmp.sg_flags); | |
1981 | + spin_unlock_irqrestore(&tty_termios_lock, flags); | |
1982 | change_termios(tty, &termios); | |
1983 | return 0; | |
1984 | } | |
1985 | @@ -374,6 +401,8 @@ | |
1986 | { | |
1987 | struct tty_struct * real_tty; | |
1988 | int retval; | |
1989 | + struct tty_ldisc *ld; | |
1990 | + unsigned long flags; | |
1991 | ||
1992 | if (tty->driver.type == TTY_DRIVER_TYPE_PTY && | |
1993 | tty->driver.subtype == PTY_TYPE_MASTER) | |
1994 | @@ -423,6 +452,8 @@ | |
1995 | retval = tty_check_change(tty); | |
1996 | if (retval) | |
1997 | return retval; | |
1998 | + | |
1999 | + ld = tty_ldisc_ref(tty); | |
2000 | switch (arg) { | |
2001 | case TCOOFF: | |
2002 | if (!tty->flow_stopped) { | |
2003 | @@ -454,20 +485,22 @@ | |
2004 | return retval; | |
2005 | switch (arg) { | |
2006 | case TCIFLUSH: | |
2007 | - if (tty->ldisc.flush_buffer) | |
2008 | - tty->ldisc.flush_buffer(tty); | |
2009 | + if (ld->flush_buffer) | |
2010 | + ld->flush_buffer(tty); | |
2011 | break; | |
2012 | case TCIOFLUSH: | |
2013 | - if (tty->ldisc.flush_buffer) | |
2014 | - tty->ldisc.flush_buffer(tty); | |
2015 | + if (ld->flush_buffer) | |
2016 | + ld->flush_buffer(tty); | |
2017 | /* fall through */ | |
2018 | case TCOFLUSH: | |
2019 | if (tty->driver.flush_buffer) | |
2020 | tty->driver.flush_buffer(tty); | |
2021 | break; | |
2022 | default: | |
2023 | + tty_ldisc_deref(ld); | |
2024 | return -EINVAL; | |
2025 | } | |
2026 | + tty_ldisc_deref(ld); | |
2027 | return 0; | |
2028 | case TIOCOUTQ: | |
2029 | return put_user(tty->driver.chars_in_buffer ? | |
2030 | @@ -515,9 +548,11 @@ | |
2031 | retval = get_user(arg, (unsigned int *) arg); | |
2032 | if (retval) | |
2033 | return retval; | |
2034 | + spin_lock_irqsave(&tty_termios_lock, flags); | |
2035 | tty->termios->c_cflag = | |
2036 | ((tty->termios->c_cflag & ~CLOCAL) | | |
2037 | (arg ? CLOCAL : 0)); | |
2038 | + spin_unlock_irqrestore(&tty_termios_lock, flags); | |
2039 | return 0; | |
2040 | default: | |
2041 | return -ENOIOCTLCMD; | |
2042 | diff -urN linux-2.2.26.orig/drivers/net/slip.c linux-2.2.26/drivers/net/slip.c | |
2043 | --- linux-2.2.26.orig/drivers/net/slip.c 2001-03-25 18:31:15.000000000 +0200 | |
2044 | +++ linux-2.2.26/drivers/net/slip.c 2004-10-24 11:09:19.428600744 +0200 | |
2045 | @@ -669,7 +669,9 @@ | |
2046 | * Handle the 'receiver data ready' interrupt. | |
2047 | * This function is called by the 'tty_io' module in the kernel when | |
2048 | * a block of SLIP data has been received, which can now be decapsulated | |
2049 | - * and sent on to some IP layer for further processing. | |
2050 | + * and sent on to some IP layer for further processing. This will not | |
2051 | + * be re-entered while running but other ldisc functions may be called | |
2052 | + * in parallel | |
2053 | */ | |
2054 | ||
2055 | static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) | |
2056 | @@ -824,9 +826,11 @@ | |
2057 | * SLIP line discipline is called for. Because we are | |
2058 | * sure the tty line exists, we only have to link it to | |
2059 | * a free SLIP channel... | |
2060 | + * | |
2061 | + * Called in process context serialized from other ldisc calls. | |
2062 | */ | |
2063 | -static int | |
2064 | -slip_open(struct tty_struct *tty) | |
2065 | + | |
2066 | +static int slip_open(struct tty_struct *tty) | |
2067 | { | |
2068 | struct slip *sl; | |
2069 | int err; | |
2070 | @@ -908,6 +912,9 @@ | |
2071 | } | |
2072 | ||
2073 | /* | |
2074 | + | |
2075 | + FIXME: 1,2 are fixed 3 was never true anyway. | |
2076 | + | |
2077 | Let me to blame a bit. | |
2078 | 1. TTY module calls this funstion on soft interrupt. | |
2079 | 2. TTY module calls this function WITH MASKED INTERRUPTS! | |
2080 | @@ -926,9 +933,8 @@ | |
2081 | ||
2082 | /* | |
2083 | * Close down a SLIP channel. | |
2084 | - * This means flushing out any pending queues, and then restoring the | |
2085 | - * TTY line discipline to what it was before it got hooked to SLIP | |
2086 | - * (which usually is TTY again). | |
2087 | + * This means flushing out any pending queues, and then returning. This | |
2088 | + * call is serialized against other ldisc functions | |
2089 | */ | |
2090 | static void | |
2091 | slip_close(struct tty_struct *tty) | |
2092 | diff -urN linux-2.2.26.orig/drivers/sbus/char/zs.c linux-2.2.26/drivers/sbus/char/zs.c | |
2093 | --- linux-2.2.26.orig/drivers/sbus/char/zs.c 2001-11-02 17:39:07.000000000 +0100 | |
2094 | +++ linux-2.2.26/drivers/sbus/char/zs.c 2004-10-31 09:43:01.192501208 +0100 | |
2095 | @@ -1606,10 +1606,10 @@ | |
2096 | tty->closing = 0; | |
2097 | info->event = 0; | |
2098 | info->tty = 0; | |
2099 | - if (tty->ldisc.num != ldiscs[N_TTY].num) { | |
2100 | + if (tty->ldisc.num != N_TTY) { | |
2101 | if (tty->ldisc.close) | |
2102 | (tty->ldisc.close)(tty); | |
2103 | - tty->ldisc = ldiscs[N_TTY]; | |
2104 | + tty->ldisc = *(tty_ldisc_get(N_TTY)); | |
2105 | tty->termios->c_line = N_TTY; | |
2106 | if (tty->ldisc.open) | |
2107 | (tty->ldisc.open)(tty); | |
2108 | diff -urN linux-2.2.26.orig/drivers/sgi/char/sgiserial.c linux-2.2.26/drivers/sgi/char/sgiserial.c | |
2109 | --- linux-2.2.26.orig/drivers/sgi/char/sgiserial.c 2001-03-25 18:31:41.000000000 +0200 | |
2110 | +++ linux-2.2.26/drivers/sgi/char/sgiserial.c 2004-10-31 09:38:06.825251832 +0100 | |
2111 | @@ -1465,10 +1465,10 @@ | |
2112 | tty->closing = 0; | |
2113 | info->event = 0; | |
2114 | info->tty = 0; | |
2115 | - if (tty->ldisc.num != ldiscs[N_TTY].num) { | |
2116 | + if (tty->ldisc.num != N_TTY) { | |
2117 | if (tty->ldisc.close) | |
2118 | (tty->ldisc.close)(tty); | |
2119 | - tty->ldisc = ldiscs[N_TTY]; | |
2120 | + tty->ldisc = *(tty_ldisc_get(N_TTY)); | |
2121 | tty->termios->c_line = N_TTY; | |
2122 | if (tty->ldisc.open) | |
2123 | (tty->ldisc.open)(tty); | |
2124 | diff -urN linux-2.2.26.orig/fs/proc/proc_tty.c linux-2.2.26/fs/proc/proc_tty.c | |
2125 | --- linux-2.2.26.orig/fs/proc/proc_tty.c 2004-02-24 14:48:05.000000000 +0100 | |
2126 | +++ linux-2.2.26/fs/proc/proc_tty.c 2004-10-31 13:07:51.212134232 +0100 | |
2127 | @@ -15,8 +15,6 @@ | |
2128 | #include <asm/bitops.h> | |
2129 | ||
2130 | extern struct tty_driver *tty_drivers; /* linked list of tty drivers */ | |
2131 | -extern struct tty_ldisc ldiscs[]; | |
2132 | - | |
2133 | ||
2134 | static int tty_drivers_read_proc(char *page, char **start, off_t off, | |
2135 | int count, int *eof, void *data); | |
2136 | @@ -112,16 +110,20 @@ | |
2137 | int len = 0; | |
2138 | off_t begin = 0; | |
2139 | off_t end; | |
2140 | + struct tty_ldisc *ld; | |
2141 | ||
2142 | end = off + count; /* XXX: undefined on overflow per ISO C99 */ | |
2143 | if (end < off) | |
2144 | return -EINVAL; | |
2145 | ||
2146 | for (i=0; i < NR_LDISCS; i++) { | |
2147 | - if (!(ldiscs[i].flags & LDISC_FLAG_DEFINED)) | |
2148 | + ld = tty_ldisc_get(i); | |
2149 | + if (ld == NULL) | |
2150 | + | |
2151 | continue; | |
2152 | len += sprintf(page+len, "%-10s %2d\n", | |
2153 | - ldiscs[i].name ? ldiscs[i].name : "???", i); | |
2154 | + ld->name ? ld->name : "???", i); | |
2155 | + tty_ldisc_put(i); | |
2156 | if (len+begin > end) | |
2157 | break; | |
2158 | if (len+begin < off) { | |
2159 | diff -urN linux-2.2.26.orig/include/linux/tty.h linux-2.2.26/include/linux/tty.h | |
2160 | --- linux-2.2.26.orig/include/linux/tty.h 2004-02-24 18:33:31.000000000 +0100 | |
2161 | +++ linux-2.2.26/include/linux/tty.h 2004-10-24 10:59:54.653459616 +0200 | |
2162 | @@ -319,19 +319,21 @@ | |
2163 | * tty->write. Thus, you must use the inline functions set_bit() and | |
2164 | * clear_bit() to make things atomic. | |
2165 | */ | |
2166 | -#define TTY_THROTTLED 0 | |
2167 | -#define TTY_IO_ERROR 1 | |
2168 | -#define TTY_OTHER_CLOSED 2 | |
2169 | -#define TTY_EXCLUSIVE 3 | |
2170 | -#define TTY_DEBUG 4 | |
2171 | -#define TTY_DO_WRITE_WAKEUP 5 | |
2172 | -#define TTY_PUSH 6 | |
2173 | -#define TTY_CLOSING 7 | |
2174 | -#define TTY_DONT_FLIP 8 | |
2175 | -#define TTY_HW_COOK_OUT 14 | |
2176 | -#define TTY_HW_COOK_IN 15 | |
2177 | -#define TTY_PTY_LOCK 16 | |
2178 | -#define TTY_NO_WRITE_SPLIT 17 | |
2179 | +#define TTY_THROTTLED 0 /* Call unthrottle() at threshold min */ | |
2180 | +#define TTY_IO_ERROR 1 /* Canse an I/O error (may be no ldisc too) */ | |
2181 | +#define TTY_OTHER_CLOSED 2 /* Other side (if any) has closed */ | |
2182 | +#define TTY_EXCLUSIVE 3 /* Exclusive open mode */ | |
2183 | +#define TTY_DEBUG 4 /* Debugging */ | |
2184 | +#define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ | |
2185 | +#define TTY_PUSH 6 /* n_tty private */ | |
2186 | +#define TTY_CLOSING 7 /* ->close() in progress */ | |
2187 | +#define TTY_DONT_FLIP 8 /* Defer buffer flip */ | |
2188 | +#define TTY_LDISC 9 /* Line discipline attached */ | |
2189 | +#define TTY_HW_COOK_OUT 14 /* Hardware can do output cooking */ | |
2190 | +#define TTY_HW_COOK_IN 15 /* Hardware can do input cooking */ | |
2191 | +#define TTY_PTY_LOCK 16 /* pty private */ | |
2192 | +#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ | |
2193 | +#define TTY_HUPPED 18 /* Post driver->hangup() */ | |
2194 | ||
2195 | #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) | |
2196 | ||
2197 | @@ -339,7 +341,7 @@ | |
2198 | ||
2199 | extern struct termios tty_std_termios; | |
2200 | extern struct tty_struct * redirect; | |
2201 | -extern struct tty_ldisc ldiscs[]; | |
2202 | +extern struct tty_ldisc tty_ldiscs[]; | |
2203 | extern int fg_console, last_console, want_console; | |
2204 | ||
2205 | extern int kmsg_redirect; | |
2206 | @@ -393,6 +395,16 @@ | |
2207 | extern void tty_flip_buffer_push(struct tty_struct *tty); | |
2208 | extern int tty_get_baud_rate(struct tty_struct *tty); | |
2209 | ||
2210 | +extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); | |
2211 | +extern void tty_ldisc_deref(struct tty_ldisc *); | |
2212 | +extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *); | |
2213 | + | |
2214 | +extern struct tty_ldisc *tty_ldisc_get(int); | |
2215 | +extern void tty_ldisc_put(int); | |
2216 | + | |
2217 | +extern void tty_wakeup(struct tty_struct *tty); | |
2218 | + | |
2219 | + | |
2220 | /* n_tty.c */ | |
2221 | extern struct tty_ldisc tty_ldisc_N_TTY; | |
2222 | ||
2223 | diff -urN linux-2.2.26.orig/include/linux/tty_ldisc.h linux-2.2.26/include/linux/tty_ldisc.h | |
2224 | --- linux-2.2.26.orig/include/linux/tty_ldisc.h 2004-02-24 18:33:31.000000000 +0100 | |
2225 | +++ linux-2.2.26/include/linux/tty_ldisc.h 2004-10-24 11:04:07.991946312 +0200 | |
2226 | @@ -129,6 +129,7 @@ | |
2227 | char *fp, int count); | |
2228 | int (*receive_room)(struct tty_struct *); | |
2229 | void (*write_wakeup)(struct tty_struct *); | |
2230 | +int refcount; | |
2231 | }; | |
2232 | ||
2233 | #define TTY_LDISC_MAGIC 0x5403 |