1 /* $NetBSD: linux_termios.c,v 1.32 2007/10/19 18:52:12 njoly Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 1998 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 and Eric Haszlakiewicz. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: linux_termios.c,v 1.32 2007/10/19 18:52:12 njoly Exp $"); 41 42 #if defined(_KERNEL_OPT) 43 #include "opt_ptm.h" 44 #endif 45 46 #include <sys/param.h> 47 #include <sys/proc.h> 48 #include <sys/systm.h> 49 #include <sys/file.h> 50 #include <sys/filedesc.h> 51 #include <sys/ioctl.h> 52 #include <sys/mount.h> 53 #include <sys/termios.h> 54 55 #include <sys/syscallargs.h> 56 57 #include <compat/linux/common/linux_types.h> 58 #include <compat/linux/common/linux_ioctl.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/common/linux_ipc.h> 63 #include <compat/linux/common/linux_sem.h> 64 65 #include <compat/linux/linux_syscallargs.h> 66 67 #ifdef DEBUG_LINUX 68 #define DPRINTF(a) uprintf a 69 #else 70 #define DPRINTF(a) 71 #endif 72 73 int 74 linux_ioctl_termios(l, uap, retval) 75 struct lwp *l; 76 struct linux_sys_ioctl_args /* { 77 syscallarg(int) fd; 78 syscallarg(u_long) com; 79 syscallarg(void *) data; 80 } */ *uap; 81 register_t *retval; 82 { 83 struct file *fp; 84 struct filedesc *fdp; 85 u_long com; 86 struct linux_termio tmplt; 87 struct linux_termios tmplts; 88 struct termios tmpbts; 89 int idat; 90 struct sys_ioctl_args ia; 91 int error; 92 char tioclinux; 93 int (*bsdioctl)(struct file *, u_long, void *, struct lwp *); 94 95 fdp = l->l_proc->p_fd; 96 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 97 return (EBADF); 98 99 FILE_USE(fp); 100 101 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 102 error = EBADF; 103 goto out; 104 } 105 106 bsdioctl = fp->f_ops->fo_ioctl; 107 com = SCARG(uap, com); 108 retval[0] = 0; 109 110 switch (com) { 111 case LINUX_TCGETS: 112 error = (*bsdioctl)(fp, TIOCGETA, (void *)&tmpbts, l); 113 if (error) 114 goto out; 115 bsd_termios_to_linux_termios(&tmpbts, &tmplts); 116 error = copyout(&tmplts, SCARG(uap, data), sizeof tmplts); 117 goto out; 118 case LINUX_TCSETS: 119 case LINUX_TCSETSW: 120 case LINUX_TCSETSF: 121 /* 122 * First fill in all fields, so that we keep the current 123 * values for fields that Linux doesn't know about. 124 */ 125 error = (*bsdioctl)(fp, TIOCGETA, (void *)&tmpbts, l); 126 if (error) 127 goto out; 128 error = copyin(SCARG(uap, data), &tmplts, sizeof tmplts); 129 if (error) 130 goto out; 131 linux_termios_to_bsd_termios(&tmplts, &tmpbts); 132 switch (com) { 133 case LINUX_TCSETS: 134 com = TIOCSETA; 135 break; 136 case LINUX_TCSETSW: 137 com = TIOCSETAW; 138 break; 139 case LINUX_TCSETSF: 140 com = TIOCSETAF; 141 break; 142 } 143 error = (*bsdioctl)(fp, com, (void *)&tmpbts, l); 144 goto out; 145 case LINUX_TCGETA: 146 error = (*bsdioctl)(fp, TIOCGETA, (void *)&tmpbts, l); 147 if (error) 148 goto out; 149 bsd_termios_to_linux_termio(&tmpbts, &tmplt); 150 error = copyout(&tmplt, SCARG(uap, data), sizeof tmplt); 151 goto out; 152 case LINUX_TCSETA: 153 case LINUX_TCSETAW: 154 case LINUX_TCSETAF: 155 /* 156 * First fill in all fields, so that we keep the current 157 * values for fields that Linux doesn't know about. 158 */ 159 error = (*bsdioctl)(fp, TIOCGETA, (void *)&tmpbts, l); 160 if (error) 161 goto out; 162 error = copyin(SCARG(uap, data), &tmplt, sizeof tmplt); 163 if (error) 164 goto out; 165 linux_termio_to_bsd_termios(&tmplt, &tmpbts); 166 switch (com) { 167 case LINUX_TCSETA: 168 com = TIOCSETA; 169 break; 170 case LINUX_TCSETAW: 171 com = TIOCSETAW; 172 break; 173 case LINUX_TCSETAF: 174 com = TIOCSETAF; 175 break; 176 } 177 error = (*bsdioctl)(fp, com, (void *)&tmpbts, l); 178 goto out; 179 case LINUX_TCFLSH: 180 switch((u_long)SCARG(uap, data)) { 181 case 0: 182 idat = FREAD; 183 break; 184 case 1: 185 idat = FWRITE; 186 break; 187 case 2: 188 idat = 0; 189 break; 190 default: 191 error = EINVAL; 192 goto out; 193 } 194 error = (*bsdioctl)(fp, TIOCFLUSH, (void *)&idat, l); 195 goto out; 196 case LINUX_TIOCGETD: 197 error = (*bsdioctl)(fp, TIOCGETD, (void *)&idat, l); 198 if (error) 199 goto out; 200 switch (idat) { 201 case TTYDISC: 202 idat = LINUX_N_TTY; 203 break; 204 case SLIPDISC: 205 idat = LINUX_N_SLIP; 206 break; 207 case PPPDISC: 208 idat = LINUX_N_PPP; 209 break; 210 case STRIPDISC: 211 idat = LINUX_N_STRIP; 212 break; 213 /* 214 * Linux does not have the tablet line discipline. 215 */ 216 case TABLDISC: 217 default: 218 idat = -1; /* XXX What should this be? */ 219 break; 220 } 221 error = copyout(&idat, SCARG(uap, data), sizeof idat); 222 goto out; 223 case LINUX_TIOCSETD: 224 error = copyin(SCARG(uap, data), &idat, sizeof idat); 225 if (error) 226 goto out; 227 switch (idat) { 228 case LINUX_N_TTY: 229 idat = TTYDISC; 230 break; 231 case LINUX_N_SLIP: 232 idat = SLIPDISC; 233 break; 234 case LINUX_N_PPP: 235 idat = PPPDISC; 236 break; 237 case LINUX_N_STRIP: 238 idat = STRIPDISC; 239 break; 240 /* 241 * We can't handle the mouse line discipline Linux has. 242 */ 243 case LINUX_N_MOUSE: 244 case LINUX_N_AX25: 245 case LINUX_N_X25: 246 case LINUX_N_6PACK: 247 default: 248 error = EINVAL; 249 goto out; 250 } 251 error = (*bsdioctl)(fp, TIOCSETD, (void *)&idat, l); 252 goto out; 253 case LINUX_TIOCLINUX: 254 error = copyin(SCARG(uap, data), &tioclinux, sizeof tioclinux); 255 if (error != 0) 256 goto out; 257 switch (tioclinux) { 258 case LINUX_TIOCLINUX_KERNMSG: 259 /* 260 * XXX needed to not fail for some things. Could 261 * try to use TIOCCONS, but the char argument 262 * specifies the VT #, not an fd. 263 */ 264 error = 0; 265 goto out; 266 case LINUX_TIOCLINUX_COPY: 267 case LINUX_TIOCLINUX_PASTE: 268 case LINUX_TIOCLINUX_UNBLANK: 269 case LINUX_TIOCLINUX_LOADLUT: 270 case LINUX_TIOCLINUX_READSHIFT: 271 case LINUX_TIOCLINUX_READMOUSE: 272 case LINUX_TIOCLINUX_VESABLANK: 273 case LINUX_TIOCLINUX_CURCONS: /* could use VT_GETACTIVE */ 274 error = EINVAL; 275 goto out; 276 } 277 break; 278 case LINUX_TIOCGWINSZ: 279 SCARG(&ia, com) = TIOCGWINSZ; 280 break; 281 case LINUX_TIOCSWINSZ: 282 SCARG(&ia, com) = TIOCSWINSZ; 283 break; 284 case LINUX_TIOCGPGRP: 285 SCARG(&ia, com) = TIOCGPGRP; 286 break; 287 case LINUX_TIOCSPGRP: 288 SCARG(&ia, com) = TIOCSPGRP; 289 break; 290 case LINUX_FIONREAD: 291 SCARG(&ia, com) = FIONREAD; 292 break; 293 case LINUX_FIONBIO: 294 SCARG(&ia, com) = FIONBIO; 295 break; 296 case LINUX_FIOASYNC: 297 SCARG(&ia, com) = FIOASYNC; 298 break; 299 case LINUX_TIOCEXCL: 300 SCARG(&ia, com) = TIOCEXCL; 301 break; 302 case LINUX_TIOCNXCL: 303 SCARG(&ia, com) = TIOCNXCL; 304 break; 305 case LINUX_TIOCCONS: 306 SCARG(&ia, com) = TIOCCONS; 307 break; 308 case LINUX_TIOCNOTTY: 309 SCARG(&ia, com) = TIOCNOTTY; 310 break; 311 case LINUX_TCSBRK: 312 SCARG(&ia, com) = SCARG(uap, data) ? TIOCDRAIN : TIOCSBRK; 313 break; 314 case LINUX_TIOCMGET: 315 SCARG(&ia, com) = TIOCMGET; 316 break; 317 case LINUX_TIOCMSET: 318 SCARG(&ia, com) = TIOCMSET; 319 break; 320 case LINUX_TIOCMBIC: 321 SCARG(&ia, com) = TIOCMBIC; 322 break; 323 case LINUX_TIOCMBIS: 324 SCARG(&ia, com) = TIOCMBIS; 325 break; 326 #ifdef LINUX_TIOCGPTN 327 case LINUX_TIOCGPTN: 328 #ifndef NO_DEV_PTM 329 { 330 struct ptmget ptm; 331 332 error = (*bsdioctl)(fp, TIOCPTSNAME, &ptm, l); 333 if (error != 0) 334 goto out; 335 error = copyout(&ptm.sfd, SCARG(uap, data), 336 sizeof(ptm.sfd)); 337 goto out; 338 } 339 #endif /* NO_DEV_PTM */ 340 #endif /* LINUX_TIOCGPTN */ 341 #ifdef LINUX_TIOCSPTLCK 342 case LINUX_TIOCSPTLCK: 343 FILE_UNUSE(fp, l); 344 error = copyin(SCARG(uap, data), &idat, sizeof(idat)); 345 if (error) 346 return error; 347 DPRINTF(("TIOCSPTLCK %d\n", idat)); 348 return 0; 349 #endif 350 default: 351 error = EINVAL; 352 goto out; 353 } 354 355 SCARG(&ia, fd) = SCARG(uap, fd); 356 SCARG(&ia, data) = SCARG(uap, data); 357 /* XXX NJWLWP */ 358 error = sys_ioctl(curlwp, &ia, retval); 359 out: 360 FILE_UNUSE(fp, l); 361 return error; 362 } 363