| .. | .. |
|---|
| 21 | 21 | #include <linux/bitops.h> |
|---|
| 22 | 22 | #include <linux/mutex.h> |
|---|
| 23 | 23 | #include <linux/compat.h> |
|---|
| 24 | +#include "tty.h" |
|---|
| 24 | 25 | |
|---|
| 25 | 26 | #include <asm/io.h> |
|---|
| 26 | 27 | #include <linux/uaccess.h> |
|---|
| .. | .. |
|---|
| 397 | 398 | tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); |
|---|
| 398 | 399 | tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); |
|---|
| 399 | 400 | |
|---|
| 400 | | - ld = tty_ldisc_ref(tty); |
|---|
| 401 | + if (opt & (TERMIOS_FLUSH|TERMIOS_WAIT)) { |
|---|
| 402 | +retry_write_wait: |
|---|
| 403 | + retval = wait_event_interruptible(tty->write_wait, !tty_chars_in_buffer(tty)); |
|---|
| 404 | + if (retval < 0) |
|---|
| 405 | + return retval; |
|---|
| 401 | 406 | |
|---|
| 402 | | - if (ld != NULL) { |
|---|
| 403 | | - if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) |
|---|
| 404 | | - ld->ops->flush_buffer(tty); |
|---|
| 405 | | - tty_ldisc_deref(ld); |
|---|
| 407 | + if (tty_write_lock(tty, 0) < 0) |
|---|
| 408 | + goto retry_write_wait; |
|---|
| 409 | + |
|---|
| 410 | + /* Racing writer? */ |
|---|
| 411 | + if (tty_chars_in_buffer(tty)) { |
|---|
| 412 | + tty_write_unlock(tty); |
|---|
| 413 | + goto retry_write_wait; |
|---|
| 414 | + } |
|---|
| 415 | + |
|---|
| 416 | + ld = tty_ldisc_ref(tty); |
|---|
| 417 | + if (ld != NULL) { |
|---|
| 418 | + if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) |
|---|
| 419 | + ld->ops->flush_buffer(tty); |
|---|
| 420 | + tty_ldisc_deref(ld); |
|---|
| 421 | + } |
|---|
| 422 | + |
|---|
| 423 | + if ((opt & TERMIOS_WAIT) && tty->ops->wait_until_sent) { |
|---|
| 424 | + tty->ops->wait_until_sent(tty, 0); |
|---|
| 425 | + if (signal_pending(current)) { |
|---|
| 426 | + tty_write_unlock(tty); |
|---|
| 427 | + return -ERESTARTSYS; |
|---|
| 428 | + } |
|---|
| 429 | + } |
|---|
| 430 | + |
|---|
| 431 | + tty_set_termios(tty, &tmp_termios); |
|---|
| 432 | + |
|---|
| 433 | + tty_write_unlock(tty); |
|---|
| 434 | + } else { |
|---|
| 435 | + tty_set_termios(tty, &tmp_termios); |
|---|
| 406 | 436 | } |
|---|
| 407 | | - |
|---|
| 408 | | - if (opt & TERMIOS_WAIT) { |
|---|
| 409 | | - tty_wait_until_sent(tty, 0); |
|---|
| 410 | | - if (signal_pending(current)) |
|---|
| 411 | | - return -ERESTARTSYS; |
|---|
| 412 | | - } |
|---|
| 413 | | - |
|---|
| 414 | | - tty_set_termios(tty, &tmp_termios); |
|---|
| 415 | 437 | |
|---|
| 416 | 438 | /* FIXME: Arguably if tmp_termios == tty->termios AND the |
|---|
| 417 | 439 | actual requested termios was not tmp_termios then we may |
|---|
| .. | .. |
|---|
| 442 | 464 | return -EFAULT; |
|---|
| 443 | 465 | return 0; |
|---|
| 444 | 466 | } |
|---|
| 445 | | - |
|---|
| 446 | | - |
|---|
| 447 | | -#ifdef TCGETX |
|---|
| 448 | | - |
|---|
| 449 | | -/** |
|---|
| 450 | | - * set_termiox - set termiox fields if possible |
|---|
| 451 | | - * @tty: terminal |
|---|
| 452 | | - * @arg: termiox structure from user |
|---|
| 453 | | - * @opt: option flags for ioctl type |
|---|
| 454 | | - * |
|---|
| 455 | | - * Implement the device calling points for the SYS5 termiox ioctl |
|---|
| 456 | | - * interface in Linux |
|---|
| 457 | | - */ |
|---|
| 458 | | - |
|---|
| 459 | | -static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) |
|---|
| 460 | | -{ |
|---|
| 461 | | - struct termiox tnew; |
|---|
| 462 | | - struct tty_ldisc *ld; |
|---|
| 463 | | - |
|---|
| 464 | | - if (tty->termiox == NULL) |
|---|
| 465 | | - return -EINVAL; |
|---|
| 466 | | - if (copy_from_user(&tnew, arg, sizeof(struct termiox))) |
|---|
| 467 | | - return -EFAULT; |
|---|
| 468 | | - |
|---|
| 469 | | - ld = tty_ldisc_ref(tty); |
|---|
| 470 | | - if (ld != NULL) { |
|---|
| 471 | | - if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) |
|---|
| 472 | | - ld->ops->flush_buffer(tty); |
|---|
| 473 | | - tty_ldisc_deref(ld); |
|---|
| 474 | | - } |
|---|
| 475 | | - if (opt & TERMIOS_WAIT) { |
|---|
| 476 | | - tty_wait_until_sent(tty, 0); |
|---|
| 477 | | - if (signal_pending(current)) |
|---|
| 478 | | - return -ERESTARTSYS; |
|---|
| 479 | | - } |
|---|
| 480 | | - |
|---|
| 481 | | - down_write(&tty->termios_rwsem); |
|---|
| 482 | | - if (tty->ops->set_termiox) |
|---|
| 483 | | - tty->ops->set_termiox(tty, &tnew); |
|---|
| 484 | | - up_write(&tty->termios_rwsem); |
|---|
| 485 | | - return 0; |
|---|
| 486 | | -} |
|---|
| 487 | | - |
|---|
| 488 | | -#endif |
|---|
| 489 | | - |
|---|
| 490 | 467 | |
|---|
| 491 | 468 | #ifdef TIOCGETP |
|---|
| 492 | 469 | /* |
|---|
| .. | .. |
|---|
| 815 | 792 | return ret; |
|---|
| 816 | 793 | #endif |
|---|
| 817 | 794 | #ifdef TCGETX |
|---|
| 818 | | - case TCGETX: { |
|---|
| 819 | | - struct termiox ktermx; |
|---|
| 820 | | - if (real_tty->termiox == NULL) |
|---|
| 821 | | - return -EINVAL; |
|---|
| 822 | | - down_read(&real_tty->termios_rwsem); |
|---|
| 823 | | - memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox)); |
|---|
| 824 | | - up_read(&real_tty->termios_rwsem); |
|---|
| 825 | | - if (copy_to_user(p, &ktermx, sizeof(struct termiox))) |
|---|
| 826 | | - ret = -EFAULT; |
|---|
| 827 | | - return ret; |
|---|
| 828 | | - } |
|---|
| 795 | + case TCGETX: |
|---|
| 829 | 796 | case TCSETX: |
|---|
| 830 | | - return set_termiox(real_tty, p, 0); |
|---|
| 831 | 797 | case TCSETXW: |
|---|
| 832 | | - return set_termiox(real_tty, p, TERMIOS_WAIT); |
|---|
| 833 | 798 | case TCSETXF: |
|---|
| 834 | | - return set_termiox(real_tty, p, TERMIOS_FLUSH); |
|---|
| 835 | | -#endif |
|---|
| 799 | + return -ENOTTY; |
|---|
| 800 | +#endif |
|---|
| 836 | 801 | case TIOCGSOFTCAR: |
|---|
| 837 | 802 | copy_termios(real_tty, &kterm); |
|---|
| 838 | 803 | ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0, |
|---|
| .. | .. |
|---|
| 866 | 831 | ld->ops->flush_buffer(tty); |
|---|
| 867 | 832 | tty_unthrottle(tty); |
|---|
| 868 | 833 | } |
|---|
| 869 | | - /* fall through */ |
|---|
| 834 | + fallthrough; |
|---|
| 870 | 835 | case TCOFLUSH: |
|---|
| 871 | 836 | tty_driver_flush_buffer(tty); |
|---|
| 872 | 837 | break; |
|---|
| .. | .. |
|---|
| 941 | 906 | } |
|---|
| 942 | 907 | } |
|---|
| 943 | 908 | EXPORT_SYMBOL(n_tty_ioctl_helper); |
|---|
| 944 | | - |
|---|
| 945 | | -#ifdef CONFIG_COMPAT |
|---|
| 946 | | -long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file, |
|---|
| 947 | | - unsigned int cmd, unsigned long arg) |
|---|
| 948 | | -{ |
|---|
| 949 | | - switch (cmd) { |
|---|
| 950 | | - case TIOCGLCKTRMIOS: |
|---|
| 951 | | - case TIOCSLCKTRMIOS: |
|---|
| 952 | | - return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg)); |
|---|
| 953 | | - default: |
|---|
| 954 | | - return -ENOIOCTLCMD; |
|---|
| 955 | | - } |
|---|
| 956 | | -} |
|---|
| 957 | | -EXPORT_SYMBOL(n_tty_compat_ioctl_helper); |
|---|
| 958 | | -#endif |
|---|
| 959 | | - |
|---|