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