1 /* $NetBSD: linux32_termios.c,v 1.12 2008/04/28 20:23:44 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 1995-2006, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden, Eric Haszlakiewicz, and Emmanuel Dreyfus. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: linux32_termios.c,v 1.12 2008/04/28 20:23:44 martin Exp $"); 34 35 #include "opt_compat_linux32.h" 36 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/time.h> 40 #include <sys/ucred.h> 41 #include <sys/proc.h> 42 #include <sys/lwp.h> 43 #include <sys/file.h> 44 #include <sys/filedesc.h> 45 #include <sys/fcntl.h> 46 #include <sys/termios.h> 47 48 #include <compat/netbsd32/netbsd32.h> 49 #include <compat/netbsd32/netbsd32_syscallargs.h> 50 51 #include <compat/linux32/common/linux32_types.h> 52 #include <compat/linux32/common/linux32_signal.h> 53 #include <compat/linux32/common/linux32_ioctl.h> 54 #include <compat/linux32/common/linux32_machdep.h> 55 #include <compat/linux32/common/linux32_termios.h> 56 #include <compat/linux32/linux32_syscallargs.h> 57 58 #include <compat/linux/common/linux_types.h> 59 #include <compat/linux/common/linux_signal.h> 60 #include <compat/linux/common/linux_util.h> 61 #include <compat/linux/common/linux_termios.h> 62 #include <compat/linux/linux_syscallargs.h> 63 64 int 65 linux32_ioctl_termios(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval) 66 { 67 /* { 68 syscallarg(int) fd; 69 syscallarg(netbsd32_u_long) com; 70 syscallarg(netbsd32_charp) data; 71 } */ 72 file_t *fp; 73 u_long com; 74 struct linux32_termio tmplt; 75 struct linux32_termios tmplts; 76 struct termios tmpbts; 77 int idat; 78 struct netbsd32_ioctl_args ia; 79 int error; 80 char tioclinux; 81 int (*bsdioctl)(file_t *, u_long, void *); 82 83 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) 84 return (EBADF); 85 86 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 87 fd_putfile(SCARG(uap, fd)); 88 error = EBADF; 89 goto out; 90 } 91 92 bsdioctl = fp->f_ops->fo_ioctl; 93 com = SCARG(uap, com); 94 retval[0] = 0; 95 96 switch (com) { 97 case LINUX32_TCGETS: 98 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 99 if (error) 100 goto out; 101 bsd_termios_to_linux32_termios(&tmpbts, &tmplts); 102 error = copyout(&tmplts, SCARG_P32(uap, data), sizeof tmplts); 103 goto out; 104 case LINUX32_TCSETS: 105 case LINUX32_TCSETSW: 106 case LINUX32_TCSETSF: 107 /* 108 * First fill in all fields, so that we keep the current 109 * values for fields that Linux doesn't know about. 110 */ 111 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 112 if (error) 113 goto out; 114 if ((error = copyin(SCARG_P32(uap, data), 115 &tmplts, sizeof tmplts)) != 0) 116 goto out; 117 linux32_termios_to_bsd_termios(&tmplts, &tmpbts); 118 switch (com) { 119 case LINUX32_TCSETS: 120 com = TIOCSETA; 121 break; 122 case LINUX32_TCSETSW: 123 com = TIOCSETAW; 124 break; 125 case LINUX32_TCSETSF: 126 com = TIOCSETAF; 127 break; 128 } 129 error = (*bsdioctl)(fp, com, &tmpbts); 130 goto out; 131 case LINUX32_TCGETA: 132 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 133 if (error) 134 goto out; 135 bsd_termios_to_linux32_termio(&tmpbts, &tmplt); 136 error = copyout(&tmplt, SCARG_P32(uap, data), sizeof tmplt); 137 goto out; 138 case LINUX32_TCSETA: 139 case LINUX32_TCSETAW: 140 case LINUX32_TCSETAF: 141 /* 142 * First fill in all fields, so that we keep the current 143 * values for fields that Linux doesn't know about. 144 */ 145 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 146 if (error) 147 goto out; 148 if ((error = copyin(SCARG_P32(uap, data), 149 &tmplt, sizeof tmplt)) != 0) 150 goto out; 151 linux32_termio_to_bsd_termios(&tmplt, &tmpbts); 152 switch (com) { 153 case LINUX32_TCSETA: 154 com = TIOCSETA; 155 break; 156 case LINUX32_TCSETAW: 157 com = TIOCSETAW; 158 break; 159 case LINUX32_TCSETAF: 160 com = TIOCSETAF; 161 break; 162 } 163 error = (*bsdioctl)(fp, com, &tmpbts); 164 goto out; 165 case LINUX32_TCFLSH: 166 switch((u_long)SCARG_P32(uap, data)) { 167 case 0: 168 idat = FREAD; 169 break; 170 case 1: 171 idat = FWRITE; 172 break; 173 case 2: 174 idat = 0; 175 break; 176 default: 177 error = EINVAL; 178 goto out; 179 } 180 error = (*bsdioctl)(fp, TIOCFLUSH, &idat); 181 goto out; 182 case LINUX32_TIOCGETD: 183 error = (*bsdioctl)(fp, TIOCGETD, &idat); 184 if (error) 185 goto out; 186 switch (idat) { 187 case TTYDISC: 188 idat = LINUX_N_TTY; 189 break; 190 case SLIPDISC: 191 idat = LINUX_N_SLIP; 192 break; 193 case PPPDISC: 194 idat = LINUX_N_PPP; 195 break; 196 case STRIPDISC: 197 idat = LINUX_N_STRIP; 198 break; 199 /* 200 * Linux does not have the tablet line discipline. 201 */ 202 case TABLDISC: 203 default: 204 idat = -1; /* XXX What should this be? */ 205 break; 206 } 207 error = copyout(&idat, SCARG_P32(uap, data), sizeof idat); 208 goto out; 209 case LINUX32_TIOCSETD: 210 if ((error = copyin(SCARG_P32(uap, data), 211 &idat, sizeof idat)) != 0) 212 goto out; 213 switch (idat) { 214 case LINUX_N_TTY: 215 idat = TTYDISC; 216 break; 217 case LINUX_N_SLIP: 218 idat = SLIPDISC; 219 break; 220 case LINUX_N_PPP: 221 idat = PPPDISC; 222 break; 223 case LINUX_N_STRIP: 224 idat = STRIPDISC; 225 break; 226 /* 227 * We can't handle the mouse line discipline Linux has. 228 */ 229 case LINUX_N_MOUSE: 230 case LINUX_N_AX25: 231 case LINUX_N_X25: 232 case LINUX_N_6PACK: 233 default: 234 error = EINVAL; 235 goto out; 236 } 237 error = (*bsdioctl)(fp, TIOCSETD, &idat); 238 goto out; 239 case LINUX32_TIOCLINUX: 240 if ((error = copyin(SCARG_P32(uap, data), 241 &tioclinux, sizeof tioclinux)) != 0) 242 goto out; 243 switch (tioclinux) { 244 case LINUX_TIOCLINUX_KERNMSG: 245 /* 246 * XXX needed to not fail for some things. Could 247 * try to use TIOCCONS, but the char argument 248 * specifies the VT #, not an fd. 249 */ 250 error = 0; 251 goto out; 252 case LINUX_TIOCLINUX_COPY: 253 case LINUX_TIOCLINUX_PASTE: 254 case LINUX_TIOCLINUX_UNBLANK: 255 case LINUX_TIOCLINUX_LOADLUT: 256 case LINUX_TIOCLINUX_READSHIFT: 257 case LINUX_TIOCLINUX_READMOUSE: 258 case LINUX_TIOCLINUX_VESABLANK: 259 case LINUX_TIOCLINUX_CURCONS: /* could use VT_GETACTIVE */ 260 error = EINVAL; 261 goto out; 262 } 263 break; 264 case LINUX32_TIOCGWINSZ: 265 SCARG(&ia, com) = TIOCGWINSZ; 266 break; 267 case LINUX32_TIOCSWINSZ: 268 SCARG(&ia, com) = TIOCSWINSZ; 269 break; 270 case LINUX32_TIOCGPGRP: 271 SCARG(&ia, com) = TIOCGPGRP; 272 break; 273 case LINUX32_TIOCSPGRP: 274 SCARG(&ia, com) = TIOCSPGRP; 275 break; 276 case LINUX32_FIONREAD: 277 SCARG(&ia, com) = FIONREAD; 278 break; 279 case LINUX32_FIONBIO: 280 SCARG(&ia, com) = FIONBIO; 281 break; 282 case LINUX32_FIOASYNC: 283 SCARG(&ia, com) = FIOASYNC; 284 break; 285 case LINUX32_TIOCEXCL: 286 SCARG(&ia, com) = TIOCEXCL; 287 break; 288 case LINUX32_TIOCNXCL: 289 SCARG(&ia, com) = TIOCNXCL; 290 break; 291 case LINUX32_TIOCCONS: 292 SCARG(&ia, com) = TIOCCONS; 293 break; 294 case LINUX32_TIOCNOTTY: 295 SCARG(&ia, com) = TIOCNOTTY; 296 break; 297 case LINUX32_TCSBRK: 298 SCARG(&ia, com) = SCARG_P32(uap, data) ? TIOCDRAIN : TIOCSBRK; 299 break; 300 case LINUX32_TIOCMGET: 301 SCARG(&ia, com) = TIOCMGET; 302 break; 303 case LINUX32_TIOCMSET: 304 SCARG(&ia, com) = TIOCMSET; 305 break; 306 case LINUX32_TIOCMBIC: 307 SCARG(&ia, com) = TIOCMBIC; 308 break; 309 case LINUX32_TIOCMBIS: 310 SCARG(&ia, com) = TIOCMBIS; 311 break; 312 #ifdef LINUX32_TIOCGPTN 313 case LINUX32_TIOCGPTN: 314 #ifndef NO_DEV_PTM 315 { 316 struct ptmget ptm; 317 318 error = (*bsdioctl)(fp, TIOCPTSNAME, &ptm); 319 if (error != 0) 320 goto out; 321 322 error = copyout(&ptm.sfd, SCARG_P32(uap, data), 323 sizeof(ptm.sfd)); 324 goto out; 325 } 326 #endif /* NO_DEV_PTM */ 327 #endif /* LINUX32_TIOCGPTN */ 328 default: 329 error = EINVAL; 330 goto out; 331 } 332 333 SCARG(&ia, fd) = SCARG(uap, fd); 334 SCARG(&ia, data) = SCARG(uap, data); 335 error = netbsd32_ioctl(curlwp, &ia, retval); 336 out: 337 fd_putfile(SCARG(uap, fd)); 338 return error; 339 } 340