diff options
author | Alan Cox <alan@lxorguk.ukuu.org.uk> | 2008-04-30 03:54:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 11:29:47 -0400 |
commit | f34d7a5b7010b82fe97da95496b9971435530062 (patch) | |
tree | 87e2abec1e33ed4fe5e63ee2fd000bc2ad745e57 /drivers/char/n_tty.c | |
parent | 251b8dd7eee30fda089a1dc088abf4fc9a0dee9c (diff) |
tty: The big operations rework
- Operations are now a shared const function block as with most other Linux
objects
- Introduce wrappers for some optional functions to get consistent behaviour
- Wrap put_char which used to be patched by the tty layer
- Document which functions are needed/optional
- Make put_char report success/fail
- Cache the driver->ops pointer in the tty as tty->ops
- Remove various surplus lock calls we no longer need
- Remove proc_write method as noted by Alexey Dobriyan
- Introduce some missing sanity checks where certain driver/ldisc
combinations would oops as they didn't check needed methods were present
[akpm@linux-foundation.org: fix fs/compat_ioctl.c build]
[akpm@linux-foundation.org: fix isicom]
[akpm@linux-foundation.org: fix arch/ia64/hp/sim/simserial.c build]
[akpm@linux-foundation.org: fix kgdb]
Signed-off-by: Alan Cox <alan@redhat.com>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/n_tty.c')
-rw-r--r-- | drivers/char/n_tty.c | 103 |
1 files changed, 43 insertions, 60 deletions
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index e1518e17e09d..abc93a93dcdd 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c | |||
@@ -149,8 +149,8 @@ static void check_unthrottle(struct tty_struct *tty) | |||
149 | { | 149 | { |
150 | if (tty->count && | 150 | if (tty->count && |
151 | test_and_clear_bit(TTY_THROTTLED, &tty->flags) && | 151 | test_and_clear_bit(TTY_THROTTLED, &tty->flags) && |
152 | tty->driver->unthrottle) | 152 | tty->ops->unthrottle) |
153 | tty->driver->unthrottle(tty); | 153 | tty->ops->unthrottle(tty); |
154 | } | 154 | } |
155 | 155 | ||
156 | /** | 156 | /** |
@@ -273,7 +273,7 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
273 | { | 273 | { |
274 | int space, spaces; | 274 | int space, spaces; |
275 | 275 | ||
276 | space = tty->driver->write_room(tty); | 276 | space = tty_write_room(tty); |
277 | if (!space) | 277 | if (!space) |
278 | return -1; | 278 | return -1; |
279 | 279 | ||
@@ -286,7 +286,7 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
286 | if (O_ONLCR(tty)) { | 286 | if (O_ONLCR(tty)) { |
287 | if (space < 2) | 287 | if (space < 2) |
288 | return -1; | 288 | return -1; |
289 | tty->driver->put_char(tty, '\r'); | 289 | tty_put_char(tty, '\r'); |
290 | tty->column = 0; | 290 | tty->column = 0; |
291 | } | 291 | } |
292 | tty->canon_column = tty->column; | 292 | tty->canon_column = tty->column; |
@@ -308,7 +308,7 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
308 | if (space < spaces) | 308 | if (space < spaces) |
309 | return -1; | 309 | return -1; |
310 | tty->column += spaces; | 310 | tty->column += spaces; |
311 | tty->driver->write(tty, " ", spaces); | 311 | tty->ops->write(tty, " ", spaces); |
312 | return 0; | 312 | return 0; |
313 | } | 313 | } |
314 | tty->column += spaces; | 314 | tty->column += spaces; |
@@ -325,7 +325,7 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
325 | break; | 325 | break; |
326 | } | 326 | } |
327 | } | 327 | } |
328 | tty->driver->put_char(tty, c); | 328 | tty_put_char(tty, c); |
329 | unlock_kernel(); | 329 | unlock_kernel(); |
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
@@ -352,7 +352,7 @@ static ssize_t opost_block(struct tty_struct *tty, | |||
352 | int i; | 352 | int i; |
353 | const unsigned char *cp; | 353 | const unsigned char *cp; |
354 | 354 | ||
355 | space = tty->driver->write_room(tty); | 355 | space = tty_write_room(tty); |
356 | if (!space) | 356 | if (!space) |
357 | return 0; | 357 | return 0; |
358 | if (nr > space) | 358 | if (nr > space) |
@@ -390,28 +390,15 @@ static ssize_t opost_block(struct tty_struct *tty, | |||
390 | } | 390 | } |
391 | } | 391 | } |
392 | break_out: | 392 | break_out: |
393 | if (tty->driver->flush_chars) | 393 | if (tty->ops->flush_chars) |
394 | tty->driver->flush_chars(tty); | 394 | tty->ops->flush_chars(tty); |
395 | i = tty->driver->write(tty, buf, i); | 395 | i = tty->ops->write(tty, buf, i); |
396 | unlock_kernel(); | 396 | unlock_kernel(); |
397 | return i; | 397 | return i; |
398 | } | 398 | } |
399 | 399 | ||
400 | 400 | ||
401 | /** | 401 | /** |
402 | * put_char - write character to driver | ||
403 | * @c: character (or part of unicode symbol) | ||
404 | * @tty: terminal device | ||
405 | * | ||
406 | * Queue a byte to the driver layer for output | ||
407 | */ | ||
408 | |||
409 | static inline void put_char(unsigned char c, struct tty_struct *tty) | ||
410 | { | ||
411 | tty->driver->put_char(tty, c); | ||
412 | } | ||
413 | |||
414 | /** | ||
415 | * echo_char - echo characters | 402 | * echo_char - echo characters |
416 | * @c: unicode byte to echo | 403 | * @c: unicode byte to echo |
417 | * @tty: terminal device | 404 | * @tty: terminal device |
@@ -423,8 +410,8 @@ static inline void put_char(unsigned char c, struct tty_struct *tty) | |||
423 | static void echo_char(unsigned char c, struct tty_struct *tty) | 410 | static void echo_char(unsigned char c, struct tty_struct *tty) |
424 | { | 411 | { |
425 | if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { | 412 | if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { |
426 | put_char('^', tty); | 413 | tty_put_char(tty, '^'); |
427 | put_char(c ^ 0100, tty); | 414 | tty_put_char(tty, c ^ 0100); |
428 | tty->column += 2; | 415 | tty->column += 2; |
429 | } else | 416 | } else |
430 | opost(c, tty); | 417 | opost(c, tty); |
@@ -433,7 +420,7 @@ static void echo_char(unsigned char c, struct tty_struct *tty) | |||
433 | static inline void finish_erasing(struct tty_struct *tty) | 420 | static inline void finish_erasing(struct tty_struct *tty) |
434 | { | 421 | { |
435 | if (tty->erasing) { | 422 | if (tty->erasing) { |
436 | put_char('/', tty); | 423 | tty_put_char(tty, '/'); |
437 | tty->column++; | 424 | tty->column++; |
438 | tty->erasing = 0; | 425 | tty->erasing = 0; |
439 | } | 426 | } |
@@ -517,7 +504,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
517 | if (L_ECHO(tty)) { | 504 | if (L_ECHO(tty)) { |
518 | if (L_ECHOPRT(tty)) { | 505 | if (L_ECHOPRT(tty)) { |
519 | if (!tty->erasing) { | 506 | if (!tty->erasing) { |
520 | put_char('\\', tty); | 507 | tty_put_char(tty, '\\'); |
521 | tty->column++; | 508 | tty->column++; |
522 | tty->erasing = 1; | 509 | tty->erasing = 1; |
523 | } | 510 | } |
@@ -525,7 +512,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
525 | echo_char(c, tty); | 512 | echo_char(c, tty); |
526 | while (--cnt > 0) { | 513 | while (--cnt > 0) { |
527 | head = (head+1) & (N_TTY_BUF_SIZE-1); | 514 | head = (head+1) & (N_TTY_BUF_SIZE-1); |
528 | put_char(tty->read_buf[head], tty); | 515 | tty_put_char(tty, tty->read_buf[head]); |
529 | } | 516 | } |
530 | } else if (kill_type == ERASE && !L_ECHOE(tty)) { | 517 | } else if (kill_type == ERASE && !L_ECHOE(tty)) { |
531 | echo_char(ERASE_CHAR(tty), tty); | 518 | echo_char(ERASE_CHAR(tty), tty); |
@@ -553,22 +540,22 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
553 | /* Now backup to that column. */ | 540 | /* Now backup to that column. */ |
554 | while (tty->column > col) { | 541 | while (tty->column > col) { |
555 | /* Can't use opost here. */ | 542 | /* Can't use opost here. */ |
556 | put_char('\b', tty); | 543 | tty_put_char(tty, '\b'); |
557 | if (tty->column > 0) | 544 | if (tty->column > 0) |
558 | tty->column--; | 545 | tty->column--; |
559 | } | 546 | } |
560 | } else { | 547 | } else { |
561 | if (iscntrl(c) && L_ECHOCTL(tty)) { | 548 | if (iscntrl(c) && L_ECHOCTL(tty)) { |
562 | put_char('\b', tty); | 549 | tty_put_char(tty, '\b'); |
563 | put_char(' ', tty); | 550 | tty_put_char(tty, ' '); |
564 | put_char('\b', tty); | 551 | tty_put_char(tty, '\b'); |
565 | if (tty->column > 0) | 552 | if (tty->column > 0) |
566 | tty->column--; | 553 | tty->column--; |
567 | } | 554 | } |
568 | if (!iscntrl(c) || L_ECHOCTL(tty)) { | 555 | if (!iscntrl(c) || L_ECHOCTL(tty)) { |
569 | put_char('\b', tty); | 556 | tty_put_char(tty, '\b'); |
570 | put_char(' ', tty); | 557 | tty_put_char(tty, ' '); |
571 | put_char('\b', tty); | 558 | tty_put_char(tty, '\b'); |
572 | if (tty->column > 0) | 559 | if (tty->column > 0) |
573 | tty->column--; | 560 | tty->column--; |
574 | } | 561 | } |
@@ -599,8 +586,7 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) | |||
599 | kill_pgrp(tty->pgrp, sig, 1); | 586 | kill_pgrp(tty->pgrp, sig, 1); |
600 | if (flush || !L_NOFLSH(tty)) { | 587 | if (flush || !L_NOFLSH(tty)) { |
601 | n_tty_flush_buffer(tty); | 588 | n_tty_flush_buffer(tty); |
602 | if (tty->driver->flush_buffer) | 589 | tty_driver_flush_buffer(tty); |
603 | tty->driver->flush_buffer(tty); | ||
604 | } | 590 | } |
605 | } | 591 | } |
606 | 592 | ||
@@ -732,7 +718,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) | |||
732 | tty->lnext = 0; | 718 | tty->lnext = 0; |
733 | if (L_ECHO(tty)) { | 719 | if (L_ECHO(tty)) { |
734 | if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { | 720 | if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { |
735 | put_char('\a', tty); /* beep if no space */ | 721 | tty_put_char(tty, '\a'); /* beep if no space */ |
736 | return; | 722 | return; |
737 | } | 723 | } |
738 | /* Record the column of first canon char. */ | 724 | /* Record the column of first canon char. */ |
@@ -776,8 +762,7 @@ send_signal: | |||
776 | */ | 762 | */ |
777 | if (!L_NOFLSH(tty)) { | 763 | if (!L_NOFLSH(tty)) { |
778 | n_tty_flush_buffer(tty); | 764 | n_tty_flush_buffer(tty); |
779 | if (tty->driver->flush_buffer) | 765 | tty_driver_flush_buffer(tty); |
780 | tty->driver->flush_buffer(tty); | ||
781 | } | 766 | } |
782 | if (L_ECHO(tty)) | 767 | if (L_ECHO(tty)) |
783 | echo_char(c, tty); | 768 | echo_char(c, tty); |
@@ -806,8 +791,8 @@ send_signal: | |||
806 | if (L_ECHO(tty)) { | 791 | if (L_ECHO(tty)) { |
807 | finish_erasing(tty); | 792 | finish_erasing(tty); |
808 | if (L_ECHOCTL(tty)) { | 793 | if (L_ECHOCTL(tty)) { |
809 | put_char('^', tty); | 794 | tty_put_char(tty, '^'); |
810 | put_char('\b', tty); | 795 | tty_put_char(tty, '\b'); |
811 | } | 796 | } |
812 | } | 797 | } |
813 | return; | 798 | return; |
@@ -828,7 +813,7 @@ send_signal: | |||
828 | if (c == '\n') { | 813 | if (c == '\n') { |
829 | if (L_ECHO(tty) || L_ECHONL(tty)) { | 814 | if (L_ECHO(tty) || L_ECHONL(tty)) { |
830 | if (tty->read_cnt >= N_TTY_BUF_SIZE-1) | 815 | if (tty->read_cnt >= N_TTY_BUF_SIZE-1) |
831 | put_char('\a', tty); | 816 | tty_put_char(tty, '\a'); |
832 | opost('\n', tty); | 817 | opost('\n', tty); |
833 | } | 818 | } |
834 | goto handle_newline; | 819 | goto handle_newline; |
@@ -846,7 +831,7 @@ send_signal: | |||
846 | */ | 831 | */ |
847 | if (L_ECHO(tty)) { | 832 | if (L_ECHO(tty)) { |
848 | if (tty->read_cnt >= N_TTY_BUF_SIZE-1) | 833 | if (tty->read_cnt >= N_TTY_BUF_SIZE-1) |
849 | put_char('\a', tty); | 834 | tty_put_char(tty, '\a'); |
850 | /* Record the column of first canon char. */ | 835 | /* Record the column of first canon char. */ |
851 | if (tty->canon_head == tty->read_head) | 836 | if (tty->canon_head == tty->read_head) |
852 | tty->canon_column = tty->column; | 837 | tty->canon_column = tty->column; |
@@ -876,7 +861,7 @@ handle_newline: | |||
876 | finish_erasing(tty); | 861 | finish_erasing(tty); |
877 | if (L_ECHO(tty)) { | 862 | if (L_ECHO(tty)) { |
878 | if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { | 863 | if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { |
879 | put_char('\a', tty); /* beep if no space */ | 864 | tty_put_char(tty, '\a'); /* beep if no space */ |
880 | return; | 865 | return; |
881 | } | 866 | } |
882 | if (c == '\n') | 867 | if (c == '\n') |
@@ -980,8 +965,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, | |||
980 | break; | 965 | break; |
981 | } | 966 | } |
982 | } | 967 | } |
983 | if (tty->driver->flush_chars) | 968 | if (tty->ops->flush_chars) |
984 | tty->driver->flush_chars(tty); | 969 | tty->ops->flush_chars(tty); |
985 | } | 970 | } |
986 | 971 | ||
987 | n_tty_set_room(tty); | 972 | n_tty_set_room(tty); |
@@ -1000,8 +985,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, | |||
1000 | if (tty->receive_room < TTY_THRESHOLD_THROTTLE) { | 985 | if (tty->receive_room < TTY_THRESHOLD_THROTTLE) { |
1001 | /* check TTY_THROTTLED first so it indicates our state */ | 986 | /* check TTY_THROTTLED first so it indicates our state */ |
1002 | if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && | 987 | if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && |
1003 | tty->driver->throttle) | 988 | tty->ops->throttle) |
1004 | tty->driver->throttle(tty); | 989 | tty->ops->throttle(tty); |
1005 | } | 990 | } |
1006 | } | 991 | } |
1007 | 992 | ||
@@ -1086,6 +1071,9 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) | |||
1086 | tty->real_raw = 0; | 1071 | tty->real_raw = 0; |
1087 | } | 1072 | } |
1088 | n_tty_set_room(tty); | 1073 | n_tty_set_room(tty); |
1074 | /* The termios change make the tty ready for I/O */ | ||
1075 | wake_up_interruptible(&tty->write_wait); | ||
1076 | wake_up_interruptible(&tty->read_wait); | ||
1089 | } | 1077 | } |
1090 | 1078 | ||
1091 | /** | 1079 | /** |
@@ -1513,11 +1501,11 @@ static ssize_t write_chan(struct tty_struct *tty, struct file *file, | |||
1513 | break; | 1501 | break; |
1514 | b++; nr--; | 1502 | b++; nr--; |
1515 | } | 1503 | } |
1516 | if (tty->driver->flush_chars) | 1504 | if (tty->ops->flush_chars) |
1517 | tty->driver->flush_chars(tty); | 1505 | tty->ops->flush_chars(tty); |
1518 | } else { | 1506 | } else { |
1519 | while (nr > 0) { | 1507 | while (nr > 0) { |
1520 | c = tty->driver->write(tty, b, nr); | 1508 | c = tty->ops->write(tty, b, nr); |
1521 | if (c < 0) { | 1509 | if (c < 0) { |
1522 | retval = c; | 1510 | retval = c; |
1523 | goto break_out; | 1511 | goto break_out; |
@@ -1554,11 +1542,6 @@ break_out: | |||
1554 | * | 1542 | * |
1555 | * This code must be sure never to sleep through a hangup. | 1543 | * This code must be sure never to sleep through a hangup. |
1556 | * Called without the kernel lock held - fine | 1544 | * Called without the kernel lock held - fine |
1557 | * | ||
1558 | * FIXME: if someone changes the VMIN or discipline settings for the | ||
1559 | * terminal while another process is in poll() the poll does not | ||
1560 | * recompute the new limits. Possibly set_termios should issue | ||
1561 | * a read wakeup to fix this bug. | ||
1562 | */ | 1545 | */ |
1563 | 1546 | ||
1564 | static unsigned int normal_poll(struct tty_struct *tty, struct file *file, | 1547 | static unsigned int normal_poll(struct tty_struct *tty, struct file *file, |
@@ -1582,9 +1565,9 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file, | |||
1582 | else | 1565 | else |
1583 | tty->minimum_to_wake = 1; | 1566 | tty->minimum_to_wake = 1; |
1584 | } | 1567 | } |
1585 | if (!tty_is_writelocked(tty) && | 1568 | if (tty->ops->write && !tty_is_writelocked(tty) && |
1586 | tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS && | 1569 | tty_chars_in_buffer(tty) < WAKEUP_CHARS && |
1587 | tty->driver->write_room(tty) > 0) | 1570 | tty_write_room(tty) > 0) |
1588 | mask |= POLLOUT | POLLWRNORM; | 1571 | mask |= POLLOUT | POLLWRNORM; |
1589 | return mask; | 1572 | return mask; |
1590 | } | 1573 | } |