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