1 /* $NetBSD: linux32_termios.c,v 1.13 2008/07/04 11:06:31 matthias 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.13 2008/07/04 11:06:31 matthias 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 #include <sys/kernel.h> 48 49 #include <compat/netbsd32/netbsd32.h> 50 #include <compat/netbsd32/netbsd32_syscallargs.h> 51 52 #include <compat/linux32/common/linux32_types.h> 53 #include <compat/linux32/common/linux32_signal.h> 54 #include <compat/linux32/common/linux32_ioctl.h> 55 #include <compat/linux32/common/linux32_machdep.h> 56 #include <compat/linux32/common/linux32_termios.h> 57 #include <compat/linux32/linux32_syscallargs.h> 58 59 #include <compat/linux/common/linux_types.h> 60 #include <compat/linux/common/linux_signal.h> 61 #include <compat/linux/common/linux_util.h> 62 #include <compat/linux/common/linux_termios.h> 63 #include <compat/linux/linux_syscallargs.h> 64 65 int 66 linux32_ioctl_termios(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval) 67 { 68 /* { 69 syscallarg(int) fd; 70 syscallarg(netbsd32_u_long) com; 71 syscallarg(netbsd32_charp) data; 72 } */ 73 file_t *fp; 74 u_long com; 75 struct linux32_termio tmplt; 76 struct linux32_termios tmplts; 77 struct termios tmpbts; 78 int idat; 79 struct netbsd32_ioctl_args ia; 80 int error; 81 char tioclinux; 82 int (*bsdioctl)(file_t *, u_long, void *); 83 84 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) 85 return (EBADF); 86 87 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 88 fd_putfile(SCARG(uap, fd)); 89 error = EBADF; 90 goto out; 91 } 92 93 bsdioctl = fp->f_ops->fo_ioctl; 94 com = SCARG(uap, com); 95 retval[0] = 0; 96 97 switch (com) { 98 case LINUX32_TCGETS: 99 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 100 if (error) 101 goto out; 102 bsd_termios_to_linux32_termios(&tmpbts, &tmplts); 103 error = copyout(&tmplts, SCARG_P32(uap, data), sizeof tmplts); 104 goto out; 105 case LINUX32_TCSETS: 106 case LINUX32_TCSETSW: 107 case LINUX32_TCSETSF: 108 /* 109 * First fill in all fields, so that we keep the current 110 * values for fields that Linux doesn't know about. 111 */ 112 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 113 if (error) 114 goto out; 115 if ((error = copyin(SCARG_P32(uap, data), 116 &tmplts, sizeof tmplts)) != 0) 117 goto out; 118 linux32_termios_to_bsd_termios(&tmplts, &tmpbts); 119 switch (com) { 120 case LINUX32_TCSETS: 121 com = TIOCSETA; 122 break; 123 case LINUX32_TCSETSW: 124 com = TIOCSETAW; 125 break; 126 case LINUX32_TCSETSF: 127 com = TIOCSETAF; 128 break; 129 } 130 error = (*bsdioctl)(fp, com, &tmpbts); 131 goto out; 132 case LINUX32_TCGETA: 133 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 134 if (error) 135 goto out; 136 bsd_termios_to_linux32_termio(&tmpbts, &tmplt); 137 error = copyout(&tmplt, SCARG_P32(uap, data), sizeof tmplt); 138 goto out; 139 case LINUX32_TCSETA: 140 case LINUX32_TCSETAW: 141 case LINUX32_TCSETAF: 142 /* 143 * First fill in all fields, so that we keep the current 144 * values for fields that Linux doesn't know about. 145 */ 146 error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); 147 if (error) 148 goto out; 149 if ((error = copyin(SCARG_P32(uap, data), 150 &tmplt, sizeof tmplt)) != 0) 151 goto out; 152 linux32_termio_to_bsd_termios(&tmplt, &tmpbts); 153 switch (com) { 154 case LINUX32_TCSETA: 155 com = TIOCSETA; 156 break; 157 case LINUX32_TCSETAW: 158 com = TIOCSETAW; 159 break; 160 case LINUX32_TCSETAF: 161 com = TIOCSETAF; 162 break; 163 } 164 error = (*bsdioctl)(fp, com, &tmpbts); 165 goto out; 166 case LINUX32_TCFLSH: 167 switch((u_long)SCARG_P32(uap, data)) { 168 case 0: 169 idat = FREAD; 170 break; 171 case 1: 172 idat = FWRITE; 173 break; 174 case 2: 175 idat = 0; 176 break; 177 default: 178 error = EINVAL; 179 goto out; 180 } 181 error = (*bsdioctl)(fp, TIOCFLUSH, &idat); 182 goto out; 183 case LINUX32_TIOCGETD: 184 error = (*bsdioctl)(fp, TIOCGETD, &idat); 185 if (error) 186 goto out; 187 switch (idat) { 188 case TTYDISC: 189 idat = LINUX_N_TTY; 190 break; 191 case SLIPDISC: 192 idat = LINUX_N_SLIP; 193 break; 194 case PPPDISC: 195 idat = LINUX_N_PPP; 196 break; 197 case STRIPDISC: 198 idat = LINUX_N_STRIP; 199 break; 200 /* 201 * Linux does not have the tablet line discipline. 202 */ 203 case TABLDISC: 204 default: 205 idat = -1; /* XXX What should this be? */ 206 break; 207 } 208 error = copyout(&idat, SCARG_P32(uap, data), sizeof idat); 209 goto out; 210 case LINUX32_TIOCSETD: 211 if ((error = copyin(SCARG_P32(uap, data), 212 &idat, sizeof idat)) != 0) 213 goto out; 214 switch (idat) { 215 case LINUX_N_TTY: 216 idat = TTYDISC; 217 break; 218 case LINUX_N_SLIP: 219 idat = SLIPDISC; 220 break; 221 case LINUX_N_PPP: 222 idat = PPPDISC; 223 break; 224 case LINUX_N_STRIP: 225 idat = STRIPDISC; 226 break; 227 /* 228 * We can't handle the mouse line discipline Linux has. 229 */ 230 case LINUX_N_MOUSE: 231 case LINUX_N_AX25: 232 case LINUX_N_X25: 233 case LINUX_N_6PACK: 234 default: 235 error = EINVAL; 236 goto out; 237 } 238 error = (*bsdioctl)(fp, TIOCSETD, &idat); 239 goto out; 240 case LINUX32_TIOCLINUX: 241 if ((error = copyin(SCARG_P32(uap, data), 242 &tioclinux, sizeof tioclinux)) != 0) 243 goto out; 244 switch (tioclinux) { 245 case LINUX_TIOCLINUX_KERNMSG: 246 /* 247 * XXX needed to not fail for some things. Could 248 * try to use TIOCCONS, but the char argument 249 * specifies the VT #, not an fd. 250 */ 251 error = 0; 252 goto out; 253 case LINUX_TIOCLINUX_COPY: 254 case LINUX_TIOCLINUX_PASTE: 255 case LINUX_TIOCLINUX_UNBLANK: 256 case LINUX_TIOCLINUX_LOADLUT: 257 case LINUX_TIOCLINUX_READSHIFT: 258 case LINUX_TIOCLINUX_READMOUSE: 259 case LINUX_TIOCLINUX_VESABLANK: 260 case LINUX_TIOCLINUX_CURCONS: /* could use VT_GETACTIVE */ 261 error = EINVAL; 262 goto out; 263 } 264 break; 265 case LINUX32_TIOCGWINSZ: 266 SCARG(&ia, com) = TIOCGWINSZ; 267 break; 268 case LINUX32_TIOCSWINSZ: 269 SCARG(&ia, com) = TIOCSWINSZ; 270 break; 271 case LINUX32_TIOCGPGRP: 272 SCARG(&ia, com) = TIOCGPGRP; 273 break; 274 case LINUX32_TIOCSPGRP: 275 SCARG(&ia, com) = TIOCSPGRP; 276 break; 277 case LINUX32_FIONREAD: 278 SCARG(&ia, com) = FIONREAD; 279 break; 280 case LINUX32_FIONBIO: 281 SCARG(&ia, com) = FIONBIO; 282 break; 283 case LINUX32_FIOASYNC: 284 SCARG(&ia, com) = FIOASYNC; 285 break; 286 case LINUX32_TIOCEXCL: 287 SCARG(&ia, com) = TIOCEXCL; 288 break; 289 case LINUX32_TIOCNXCL: 290 SCARG(&ia, com) = TIOCNXCL; 291 break; 292 case LINUX32_TIOCCONS: 293 SCARG(&ia, com) = TIOCCONS; 294 break; 295 case LINUX32_TIOCNOTTY: 296 SCARG(&ia, com) = TIOCNOTTY; 297 break; 298 case LINUX32_TCSBRK: 299 idat = (u_long)SCARG_P32(uap, data); 300 if (idat != 0) 301 SCARG(&ia, com) = TIOCDRAIN; 302 else { 303 if ((error = (*bsdioctl)(fp, TIOCSBRK, NULL)) != 0) 304 goto out; 305 error = tsleep(&idat, PZERO | PCATCH, "linux_tcsbrk", hz / 4); 306 if (error == EINTR || error == ERESTART) { 307 (void)(*bsdioctl)(fp, TIOCCBRK, NULL); 308 error = EINTR; 309 } else 310 error = (*bsdioctl)(fp, TIOCCBRK, NULL); 311 goto out; 312 } 313 break; 314 case LINUX32_TIOCMGET: 315 SCARG(&ia, com) = TIOCMGET; 316 break; 317 case LINUX32_TIOCMSET: 318 SCARG(&ia, com) = TIOCMSET; 319 break; 320 case LINUX32_TIOCMBIC: 321 SCARG(&ia, com) = TIOCMBIC; 322 break; 323 case LINUX32_TIOCMBIS: 324 SCARG(&ia, com) = TIOCMBIS; 325 break; 326 #ifdef LINUX32_TIOCGPTN 327 case LINUX32_TIOCGPTN: 328 #ifndef NO_DEV_PTM 329 { 330 struct ptmget ptm; 331 332 error = (*bsdioctl)(fp, TIOCPTSNAME, &ptm); 333 if (error != 0) 334 goto out; 335 336 error = copyout(&ptm.sfd, SCARG_P32(uap, data), 337 sizeof(ptm.sfd)); 338 goto out; 339 } 340 #endif /* NO_DEV_PTM */ 341 #endif /* LINUX32_TIOCGPTN */ 342 default: 343 error = EINVAL; 344 goto out; 345 } 346 347 SCARG(&ia, fd) = SCARG(uap, fd); 348 SCARG(&ia, data) = SCARG(uap, data); 349 error = netbsd32_ioctl(curlwp, &ia, retval); 350 out: 351 fd_putfile(SCARG(uap, fd)); 352 return error; 353 } 354