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