1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/termios_internal.h> 3 4 /* 5 * c_cc characters in the termio structure. Oh, how I love being 6 * backwardly compatible. Notice that character 4 and 5 are 7 * interpreted differently depending on whether ICANON is set in 8 * c_lflag. If it's set, they are used as _VEOF and _VEOL, otherwise 9 * as _VMIN and V_TIME. This is for compatibility with OSF/1 (which 10 * is compatible with sysV)... 11 */ 12 #define _VMIN 4 13 #define _VTIME 5 14 15 int kernel_termios_to_user_termio(struct termio __user *termio, 16 struct ktermios *termios) 17 { 18 struct termio v; 19 memset(&v, 0, sizeof(struct termio)); 20 v.c_iflag = termios->c_iflag; 21 v.c_oflag = termios->c_oflag; 22 v.c_cflag = termios->c_cflag; 23 v.c_lflag = termios->c_lflag; 24 v.c_line = termios->c_line; 25 memcpy(v.c_cc, termios->c_cc, NCC); 26 if (!(v.c_lflag & ICANON)) { 27 v.c_cc[_VMIN] = termios->c_cc[VMIN]; 28 v.c_cc[_VTIME] = termios->c_cc[VTIME]; 29 } 30 return copy_to_user(termio, &v, sizeof(struct termio)); 31 } 32 33 int user_termios_to_kernel_termios(struct ktermios *k, 34 struct termios2 __user *u) 35 { 36 int err; 37 err = get_user(k->c_iflag, &u->c_iflag); 38 err |= get_user(k->c_oflag, &u->c_oflag); 39 err |= get_user(k->c_cflag, &u->c_cflag); 40 err |= get_user(k->c_lflag, &u->c_lflag); 41 err |= get_user(k->c_line, &u->c_line); 42 err |= copy_from_user(k->c_cc, u->c_cc, NCCS); 43 if (k->c_lflag & ICANON) { 44 err |= get_user(k->c_cc[VEOF], &u->c_cc[VEOF]); 45 err |= get_user(k->c_cc[VEOL], &u->c_cc[VEOL]); 46 } else { 47 err |= get_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); 48 err |= get_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); 49 } 50 err |= get_user(k->c_ispeed, &u->c_ispeed); 51 err |= get_user(k->c_ospeed, &u->c_ospeed); 52 return err; 53 } 54 55 int kernel_termios_to_user_termios(struct termios2 __user *u, 56 struct ktermios *k) 57 { 58 int err; 59 err = put_user(k->c_iflag, &u->c_iflag); 60 err |= put_user(k->c_oflag, &u->c_oflag); 61 err |= put_user(k->c_cflag, &u->c_cflag); 62 err |= put_user(k->c_lflag, &u->c_lflag); 63 err |= put_user(k->c_line, &u->c_line); 64 err |= copy_to_user(u->c_cc, k->c_cc, NCCS); 65 if (!(k->c_lflag & ICANON)) { 66 err |= put_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); 67 err |= put_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); 68 } else { 69 err |= put_user(k->c_cc[VEOF], &u->c_cc[VEOF]); 70 err |= put_user(k->c_cc[VEOL], &u->c_cc[VEOL]); 71 } 72 err |= put_user(k->c_ispeed, &u->c_ispeed); 73 err |= put_user(k->c_ospeed, &u->c_ospeed); 74 return err; 75 } 76 77 int user_termios_to_kernel_termios_1(struct ktermios *k, 78 struct termios __user *u) 79 { 80 int err; 81 err = get_user(k->c_iflag, &u->c_iflag); 82 err |= get_user(k->c_oflag, &u->c_oflag); 83 err |= get_user(k->c_cflag, &u->c_cflag); 84 err |= get_user(k->c_lflag, &u->c_lflag); 85 err |= get_user(k->c_line, &u->c_line); 86 err |= copy_from_user(k->c_cc, u->c_cc, NCCS); 87 if (k->c_lflag & ICANON) { 88 err |= get_user(k->c_cc[VEOF], &u->c_cc[VEOF]); 89 err |= get_user(k->c_cc[VEOL], &u->c_cc[VEOL]); 90 } else { 91 err |= get_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); 92 err |= get_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); 93 } 94 return err; 95 } 96 97 int kernel_termios_to_user_termios_1(struct termios __user *u, 98 struct ktermios *k) 99 { 100 int err; 101 err = put_user(k->c_iflag, &u->c_iflag); 102 err |= put_user(k->c_oflag, &u->c_oflag); 103 err |= put_user(k->c_cflag, &u->c_cflag); 104 err |= put_user(k->c_lflag, &u->c_lflag); 105 err |= put_user(k->c_line, &u->c_line); 106 err |= copy_to_user(u->c_cc, k->c_cc, NCCS); 107 if (!(k->c_lflag & ICANON)) { 108 err |= put_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); 109 err |= put_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); 110 } else { 111 err |= put_user(k->c_cc[VEOF], &u->c_cc[VEOF]); 112 err |= put_user(k->c_cc[VEOL], &u->c_cc[VEOL]); 113 } 114 return err; 115 } 116