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