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