.. | .. |
---|
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 | | - |
---|