1 /* $NetBSD: linux_termios.c,v 1.26 2006/09/22 15:12:02 christos 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.26 2006/09/22 15:12:02 christos 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/sa.h> 56 #include <sys/syscallargs.h> 57 58 #include <compat/linux/common/linux_types.h> 59 #include <compat/linux/common/linux_ioctl.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 64 #include <compat/linux/linux_syscallargs.h> 65 66 #ifdef DEBUG_LINUX 67 #define DPRINTF(a) uprintf a 68 #else 69 #define DPRINTF(a) 70 #endif 71 72 int 73 linux_ioctl_termios(l, uap, retval) 74 struct lwp *l; 75 struct linux_sys_ioctl_args /* { 76 syscallarg(int) fd; 77 syscallarg(u_long) com; 78 syscallarg(caddr_t) data; 79 } */ *uap; 80 register_t *retval; 81 { 82 struct file *fp; 83 struct filedesc *fdp; 84 u_long com; 85 struct linux_termio tmplt; 86 struct linux_termios tmplts; 87 struct termios tmpbts; 88 int idat; 89 struct sys_ioctl_args ia; 90 int error; 91 char tioclinux; 92 int (*bsdioctl)(struct file *, u_long, void *, struct lwp *); 93 94 fdp = l->l_proc->p_fd; 95 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 96 return (EBADF); 97 98 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 99 error = EBADF; 100 goto out; 101 } 102 103 FILE_USE(fp); 104 105 bsdioctl = fp->f_ops->fo_ioctl; 106 com = SCARG(uap, com); 107 retval[0] = 0; 108 109 switch (com & 0xffff) { 110 case LINUX_TCGETS: 111 error = (*bsdioctl)(fp, TIOCGETA, (caddr_t)&tmpbts, l); 112 if (error) 113 goto out; 114 bsd_termios_to_linux_termios(&tmpbts, &tmplts); 115 error = copyout(&tmplts, SCARG(uap, data), sizeof tmplts); 116 goto out; 117 case LINUX_TCSETS: 118 case LINUX_TCSETSW: 119 case LINUX_TCSETSF: 120 /* 121 * First fill in all fields, so that we keep the current 122 * values for fields that Linux doesn't know about. 123 */ 124 error = (*bsdioctl)(fp, TIOCGETA, (caddr_t)&tmpbts, l); 125 if (error) 126 goto out; 127 error = copyin(SCARG(uap, data), &tmplts, sizeof tmplts); 128 if (error) 129 goto out; 130 linux_termios_to_bsd_termios(&tmplts, &tmpbts); 131 switch (com) { 132 case LINUX_TCSETS: 133 com = TIOCSETA; 134 break; 135 case LINUX_TCSETSW: 136 com = TIOCSETAW; 137 break; 138 case LINUX_TCSETSF: 139 com = TIOCSETAF; 140 break; 141 } 142 error = (*bsdioctl)(fp, com, (caddr_t)&tmpbts, l); 143 goto out; 144 case LINUX_TCGETA: 145 error = (*bsdioctl)(fp, TIOCGETA, (caddr_t)&tmpbts, l); 146 if (error) 147 goto out; 148 bsd_termios_to_linux_termio(&tmpbts, &tmplt); 149 error = copyout(&tmplt, SCARG(uap, data), sizeof tmplt); 150 goto out; 151 case LINUX_TCSETA: 152 case LINUX_TCSETAW: 153 case LINUX_TCSETAF: 154 /* 155 * First fill in all fields, so that we keep the current 156 * values for fields that Linux doesn't know about. 157 */ 158 error = (*bsdioctl)(fp, TIOCGETA, (caddr_t)&tmpbts, l); 159 if (error) 160 goto out; 161 error = copyin(SCARG(uap, data), &tmplt, sizeof tmplt); 162 if (error) 163 goto out; 164 linux_termio_to_bsd_termios(&tmplt, &tmpbts); 165 switch (com) { 166 case LINUX_TCSETA: 167 com = TIOCSETA; 168 break; 169 case LINUX_TCSETAW: 170 com = TIOCSETAW; 171 break; 172 case LINUX_TCSETAF: 173 com = TIOCSETAF; 174 break; 175 } 176 error = (*bsdioctl)(fp, com, (caddr_t)&tmpbts, l); 177 goto out; 178 case LINUX_TCFLSH: 179 switch((u_long)SCARG(uap, data)) { 180 case 0: 181 idat = FREAD; 182 break; 183 case 1: 184 idat = FWRITE; 185 break; 186 case 2: 187 idat = 0; 188 break; 189 default: 190 error = EINVAL; 191 goto out; 192 } 193 error = (*bsdioctl)(fp, TIOCFLUSH, (caddr_t)&idat, l); 194 goto out; 195 case LINUX_TIOCGETD: 196 error = (*bsdioctl)(fp, TIOCGETD, (caddr_t)&idat, l); 197 if (error) 198 goto out; 199 switch (idat) { 200 case TTYDISC: 201 idat = LINUX_N_TTY; 202 break; 203 case SLIPDISC: 204 idat = LINUX_N_SLIP; 205 break; 206 case PPPDISC: 207 idat = LINUX_N_PPP; 208 break; 209 case STRIPDISC: 210 idat = LINUX_N_STRIP; 211 break; 212 /* 213 * Linux does not have the tablet line discipline. 214 */ 215 case TABLDISC: 216 default: 217 idat = -1; /* XXX What should this be? */ 218 break; 219 } 220 error = copyout(&idat, SCARG(uap, data), sizeof idat); 221 goto out; 222 case LINUX_TIOCSETD: 223 error = copyin(SCARG(uap, data), &idat, sizeof idat); 224 if (error) 225 goto out; 226 switch (idat) { 227 case LINUX_N_TTY: 228 idat = TTYDISC; 229 break; 230 case LINUX_N_SLIP: 231 idat = SLIPDISC; 232 break; 233 case LINUX_N_PPP: 234 idat = PPPDISC; 235 break; 236 case LINUX_N_STRIP: 237 idat = STRIPDISC; 238 break; 239 /* 240 * We can't handle the mouse line discipline Linux has. 241 */ 242 case LINUX_N_MOUSE: 243 case LINUX_N_AX25: 244 case LINUX_N_X25: 245 case LINUX_N_6PACK: 246 default: 247 error = EINVAL; 248 goto out; 249 } 250 error = (*bsdioctl)(fp, TIOCSETD, (caddr_t)&idat, l); 251 goto out; 252 case LINUX_TIOCLINUX: 253 error = copyin(SCARG(uap, data), &tioclinux, sizeof tioclinux); 254 if (error != 0) 255 goto out; 256 switch (tioclinux) { 257 case LINUX_TIOCLINUX_KERNMSG: 258 /* 259 * XXX needed to not fail for some things. Could 260 * try to use TIOCCONS, but the char argument 261 * specifies the VT #, not an fd. 262 */ 263 error = 0; 264 goto out; 265 case LINUX_TIOCLINUX_COPY: 266 case LINUX_TIOCLINUX_PASTE: 267 case LINUX_TIOCLINUX_UNBLANK: 268 case LINUX_TIOCLINUX_LOADLUT: 269 case LINUX_TIOCLINUX_READSHIFT: 270 case LINUX_TIOCLINUX_READMOUSE: 271 case LINUX_TIOCLINUX_VESABLANK: 272 case LINUX_TIOCLINUX_CURCONS: /* could use VT_GETACTIVE */ 273 error = EINVAL; 274 goto out; 275 } 276 break; 277 case LINUX_TIOCGWINSZ: 278 SCARG(&ia, com) = TIOCGWINSZ; 279 break; 280 case LINUX_TIOCSWINSZ: 281 SCARG(&ia, com) = TIOCSWINSZ; 282 break; 283 case LINUX_TIOCGPGRP: 284 SCARG(&ia, com) = TIOCGPGRP; 285 break; 286 case LINUX_TIOCSPGRP: 287 SCARG(&ia, com) = TIOCSPGRP; 288 break; 289 case LINUX_FIONREAD: 290 SCARG(&ia, com) = FIONREAD; 291 break; 292 case LINUX_FIONBIO: 293 SCARG(&ia, com) = FIONBIO; 294 break; 295 case LINUX_FIOASYNC: 296 SCARG(&ia, com) = FIOASYNC; 297 break; 298 case LINUX_TIOCEXCL: 299 SCARG(&ia, com) = TIOCEXCL; 300 break; 301 case LINUX_TIOCNXCL: 302 SCARG(&ia, com) = TIOCNXCL; 303 break; 304 case LINUX_TIOCCONS: 305 SCARG(&ia, com) = TIOCCONS; 306 break; 307 case LINUX_TIOCNOTTY: 308 SCARG(&ia, com) = TIOCNOTTY; 309 break; 310 case LINUX_TCSBRK: 311 SCARG(&ia, com) = SCARG(uap, data) ? TIOCDRAIN : TIOCSBRK; 312 break; 313 case LINUX_TIOCMGET: 314 SCARG(&ia, com) = TIOCMGET; 315 break; 316 case LINUX_TIOCMSET: 317 SCARG(&ia, com) = TIOCMSET; 318 break; 319 case LINUX_TIOCMBIC: 320 SCARG(&ia, com) = TIOCMBIC; 321 break; 322 case LINUX_TIOCMBIS: 323 SCARG(&ia, com) = TIOCMBIS; 324 break; 325 #ifdef LINUX_TIOCGPTN 326 case LINUX_TIOCGPTN: 327 #ifndef NO_DEV_PTM 328 { 329 caddr_t sg = stackgap_init(l->l_proc, 0); 330 struct ptmget ptm, *ptmp = stackgap_alloc(l->l_proc, &sg, 331 sizeof(*ptmp)); 332 333 SCARG(&ia, fd) = SCARG(uap, fd); 334 SCARG(&ia, com) = TIOCPTSNAME; 335 SCARG(&ia, data) = ptmp; 336 337 if ((error = sys_ioctl(curlwp, &ia, retval)) != 0) 338 goto out; 339 340 if ((error = copyin(ptmp, &ptm, sizeof(ptm))) != 0) 341 printf("copyin %d\n", error); 342 343 error = copyout(&ptm.sfd, SCARG(uap, data), 344 sizeof(ptm.sfd)); 345 goto out; 346 } 347 #endif /* NO_DEV_PTM */ 348 #endif /* LINUX_TIOCGPTN */ 349 #ifdef LINUX_TIOCSPTLCK 350 case LINUX_TIOCSPTLCK: 351 FILE_UNUSE(fp, l); 352 error = copyin(SCARG(uap, data), &idat, sizeof(idat)); 353 if (error) 354 return error; 355 DPRINTF(("TIOCSPTLCK %d\n", idat)); 356 return 0; 357 #endif 358 default: 359 error = EINVAL; 360 goto out; 361 } 362 363 SCARG(&ia, fd) = SCARG(uap, fd); 364 SCARG(&ia, data) = SCARG(uap, data); 365 /* XXX NJWLWP */ 366 error = sys_ioctl(curlwp, &ia, retval); 367 out: 368 FILE_UNUSE(fp, l); 369 return error; 370 } 371