| // SPDX-License-Identifier: GPL-2.0 | |
| #include <linux/termios_internal.h> | |
| /* | |
| * c_cc characters in the termio structure. Oh, how I love being | |
| * backwardly compatible. Notice that character 4 and 5 are | |
| * interpreted differently depending on whether ICANON is set in | |
| * c_lflag. If it's set, they are used as _VEOF and _VEOL, otherwise | |
| * as _VMIN and V_TIME. This is for compatibility with OSF/1 (which | |
| * is compatible with sysV)... | |
| */ | |
| #define _VMIN 4 | |
| #define _VTIME 5 | |
| int kernel_termios_to_user_termio(struct termio __user *termio, | |
| struct ktermios *termios) | |
| { | |
| struct termio v; | |
| memset(&v, 0, sizeof(struct termio)); | |
| v.c_iflag = termios->c_iflag; | |
| v.c_oflag = termios->c_oflag; | |
| v.c_cflag = termios->c_cflag; | |
| v.c_lflag = termios->c_lflag; | |
| v.c_line = termios->c_line; | |
| memcpy(v.c_cc, termios->c_cc, NCC); | |
| if (!(v.c_lflag & ICANON)) { | |
| v.c_cc[_VMIN] = termios->c_cc[VMIN]; | |
| v.c_cc[_VTIME] = termios->c_cc[VTIME]; | |
| } | |
| return copy_to_user(termio, &v, sizeof(struct termio)); | |
| } | |
| int user_termios_to_kernel_termios(struct ktermios *k, | |
| struct termios2 __user *u) | |
| { | |
| int err; | |
| err = get_user(k->c_iflag, &u->c_iflag); | |
| err |= get_user(k->c_oflag, &u->c_oflag); | |
| err |= get_user(k->c_cflag, &u->c_cflag); | |
| err |= get_user(k->c_lflag, &u->c_lflag); | |
| err |= get_user(k->c_line, &u->c_line); | |
| err |= copy_from_user(k->c_cc, u->c_cc, NCCS); | |
| if (k->c_lflag & ICANON) { | |
| err |= get_user(k->c_cc[VEOF], &u->c_cc[VEOF]); | |
| err |= get_user(k->c_cc[VEOL], &u->c_cc[VEOL]); | |
| } else { | |
| err |= get_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); | |
| err |= get_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); | |
| } | |
| err |= get_user(k->c_ispeed, &u->c_ispeed); | |
| err |= get_user(k->c_ospeed, &u->c_ospeed); | |
| return err; | |
| } | |
| int kernel_termios_to_user_termios(struct termios2 __user *u, | |
| struct ktermios *k) | |
| { | |
| int err; | |
| err = put_user(k->c_iflag, &u->c_iflag); | |
| err |= put_user(k->c_oflag, &u->c_oflag); | |
| err |= put_user(k->c_cflag, &u->c_cflag); | |
| err |= put_user(k->c_lflag, &u->c_lflag); | |
| err |= put_user(k->c_line, &u->c_line); | |
| err |= copy_to_user(u->c_cc, k->c_cc, NCCS); | |
| if (!(k->c_lflag & ICANON)) { | |
| err |= put_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); | |
| err |= put_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); | |
| } else { | |
| err |= put_user(k->c_cc[VEOF], &u->c_cc[VEOF]); | |
| err |= put_user(k->c_cc[VEOL], &u->c_cc[VEOL]); | |
| } | |
| err |= put_user(k->c_ispeed, &u->c_ispeed); | |
| err |= put_user(k->c_ospeed, &u->c_ospeed); | |
| return err; | |
| } | |
| int user_termios_to_kernel_termios_1(struct ktermios *k, | |
| struct termios __user *u) | |
| { | |
| int err; | |
| err = get_user(k->c_iflag, &u->c_iflag); | |
| err |= get_user(k->c_oflag, &u->c_oflag); | |
| err |= get_user(k->c_cflag, &u->c_cflag); | |
| err |= get_user(k->c_lflag, &u->c_lflag); | |
| err |= get_user(k->c_line, &u->c_line); | |
| err |= copy_from_user(k->c_cc, u->c_cc, NCCS); | |
| if (k->c_lflag & ICANON) { | |
| err |= get_user(k->c_cc[VEOF], &u->c_cc[VEOF]); | |
| err |= get_user(k->c_cc[VEOL], &u->c_cc[VEOL]); | |
| } else { | |
| err |= get_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); | |
| err |= get_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); | |
| } | |
| return err; | |
| } | |
| int kernel_termios_to_user_termios_1(struct termios __user *u, | |
| struct ktermios *k) | |
| { | |
| int err; | |
| err = put_user(k->c_iflag, &u->c_iflag); | |
| err |= put_user(k->c_oflag, &u->c_oflag); | |
| err |= put_user(k->c_cflag, &u->c_cflag); | |
| err |= put_user(k->c_lflag, &u->c_lflag); | |
| err |= put_user(k->c_line, &u->c_line); | |
| err |= copy_to_user(u->c_cc, k->c_cc, NCCS); | |
| if (!(k->c_lflag & ICANON)) { | |
| err |= put_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); | |
| err |= put_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); | |
| } else { | |
| err |= put_user(k->c_cc[VEOF], &u->c_cc[VEOF]); | |
| err |= put_user(k->c_cc[VEOL], &u->c_cc[VEOL]); | |
| } | |
| return err; | |
| } |