1 /* $NetBSD: tty_43.c,v 1.29 2008/11/19 18:36:02 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /*- 30 * Copyright (c) 1982, 1986, 1991, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. Neither the name of the University nor the names of its contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 * 57 * @(#)tty_compat.c 8.2 (Berkeley) 1/9/95 58 */ 59 60 /* 61 * mapping routines for old line discipline (yuck) 62 */ 63 64 #include <sys/cdefs.h> 65 __KERNEL_RCSID(0, "$NetBSD: tty_43.c,v 1.29 2008/11/19 18:36:02 ad Exp $"); 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/ioctl.h> 70 #include <sys/proc.h> 71 #include <sys/conf.h> 72 #include <sys/tty.h> 73 #include <sys/termios.h> 74 #include <sys/file.h> 75 #include <sys/kernel.h> 76 #include <sys/syslog.h> 77 #include <sys/ioctl_compat.h> 78 79 int ttydebug = 0; 80 81 static const struct speedtab compatspeeds[] = { 82 #define MAX_SPEED 17 83 { 115200, 17 }, 84 { 57600, 16 }, 85 { 38400, 15 }, 86 { 19200, 14 }, 87 { 9600, 13 }, 88 { 4800, 12 }, 89 { 2400, 11 }, 90 { 1800, 10 }, 91 { 1200, 9 }, 92 { 600, 8 }, 93 { 300, 7 }, 94 { 200, 6 }, 95 { 150, 5 }, 96 { 134, 4 }, 97 { 110, 3 }, 98 { 75, 2 }, 99 { 50, 1 }, 100 { 0, 0 }, 101 { -1, -1 }, 102 }; 103 static const int compatspcodes[] = { 104 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 105 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200 106 }; 107 108 static int ttcompatgetflags(struct tty *); 109 static void ttcompatsetflags(struct tty *, struct termios *); 110 static void ttcompatsetlflags(struct tty *, struct termios *); 111 int ttcompat(struct tty *, u_long, void *, int, struct lwp *); 112 113 /*ARGSUSED*/ 114 int 115 ttcompat(struct tty *tp, u_long com, void *data, int flag, struct lwp *l) 116 { 117 118 switch (com) { 119 case TIOCGETP: { 120 struct sgttyb *sg = (struct sgttyb *)data; 121 u_char *cc; 122 int speed; 123 124 mutex_spin_enter(&tty_lock); 125 cc = tp->t_cc; 126 speed = ttspeedtab(tp->t_ospeed, compatspeeds); 127 sg->sg_ospeed = (speed == -1) ? MAX_SPEED : speed; 128 if (tp->t_ispeed == 0) 129 sg->sg_ispeed = sg->sg_ospeed; 130 else { 131 speed = ttspeedtab(tp->t_ispeed, compatspeeds); 132 sg->sg_ispeed = (speed == -1) ? MAX_SPEED : speed; 133 } 134 sg->sg_erase = cc[VERASE]; 135 sg->sg_kill = cc[VKILL]; 136 sg->sg_flags = ttcompatgetflags(tp); 137 mutex_spin_exit(&tty_lock); 138 break; 139 } 140 141 case TIOCSETP: 142 case TIOCSETN: { 143 struct sgttyb *sg = (struct sgttyb *)data; 144 struct termios term; 145 int speed; 146 147 mutex_spin_enter(&tty_lock); 148 term = tp->t_termios; 149 if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0) 150 term.c_ispeed = speed; 151 else 152 term.c_ispeed = compatspcodes[speed]; 153 if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0) 154 term.c_ospeed = speed; 155 else 156 term.c_ospeed = compatspcodes[speed]; 157 term.c_cc[VERASE] = sg->sg_erase; 158 term.c_cc[VKILL] = sg->sg_kill; 159 tp->t_flags = (ttcompatgetflags(tp)&0xffff0000) | (sg->sg_flags&0xffff); 160 ttcompatsetflags(tp, &term); 161 mutex_spin_exit(&tty_lock); 162 return (ttioctl(tp, com == TIOCSETP ? TIOCSETAF : TIOCSETA, 163 (void *)&term, flag, l)); 164 } 165 166 case TIOCGETC: { 167 struct tchars *tc = (struct tchars *)data; 168 u_char *cc = tp->t_cc; 169 170 tc->t_intrc = cc[VINTR]; 171 tc->t_quitc = cc[VQUIT]; 172 tc->t_startc = cc[VSTART]; 173 tc->t_stopc = cc[VSTOP]; 174 tc->t_eofc = cc[VEOF]; 175 tc->t_brkc = cc[VEOL]; 176 break; 177 } 178 case TIOCSETC: { 179 struct tchars *tc = (struct tchars *)data; 180 u_char *cc = tp->t_cc; 181 182 cc[VINTR] = tc->t_intrc; 183 cc[VQUIT] = tc->t_quitc; 184 cc[VSTART] = tc->t_startc; 185 cc[VSTOP] = tc->t_stopc; 186 cc[VEOF] = tc->t_eofc; 187 cc[VEOL] = tc->t_brkc; 188 if (tc->t_brkc == (char)-1) 189 cc[VEOL2] = _POSIX_VDISABLE; 190 break; 191 } 192 case TIOCSLTC: { 193 struct ltchars *ltc = (struct ltchars *)data; 194 u_char *cc = tp->t_cc; 195 196 cc[VSUSP] = ltc->t_suspc; 197 cc[VDSUSP] = ltc->t_dsuspc; 198 cc[VREPRINT] = ltc->t_rprntc; 199 cc[VDISCARD] = ltc->t_flushc; 200 cc[VWERASE] = ltc->t_werasc; 201 cc[VLNEXT] = ltc->t_lnextc; 202 break; 203 } 204 case TIOCGLTC: { 205 struct ltchars *ltc = (struct ltchars *)data; 206 u_char *cc = tp->t_cc; 207 208 ltc->t_suspc = cc[VSUSP]; 209 ltc->t_dsuspc = cc[VDSUSP]; 210 ltc->t_rprntc = cc[VREPRINT]; 211 ltc->t_flushc = cc[VDISCARD]; 212 ltc->t_werasc = cc[VWERASE]; 213 ltc->t_lnextc = cc[VLNEXT]; 214 break; 215 } 216 case TIOCLBIS: 217 case TIOCLBIC: 218 case TIOCLSET: { 219 struct termios term; 220 int flags; 221 222 mutex_spin_enter(&tty_lock); 223 term = tp->t_termios; 224 flags = ttcompatgetflags(tp); 225 switch (com) { 226 case TIOCLSET: 227 tp->t_flags = (flags&0xffff) | (*(int *)data<<16); 228 break; 229 case TIOCLBIS: 230 tp->t_flags = flags | (*(int *)data<<16); 231 break; 232 case TIOCLBIC: 233 tp->t_flags = flags & ~(*(int *)data<<16); 234 break; 235 } 236 ttcompatsetlflags(tp, &term); 237 mutex_spin_exit(&tty_lock); 238 return (ttioctl(tp, TIOCSETA, (void *)&term, flag, l)); 239 } 240 case TIOCLGET: 241 mutex_spin_enter(&tty_lock); 242 *(int *)data = ttcompatgetflags(tp)>>16; 243 mutex_spin_exit(&tty_lock); 244 if (ttydebug) 245 printf("CLGET: returning %x\n", *(int *)data); 246 break; 247 248 case OTIOCGETD: 249 mutex_spin_enter(&tty_lock); 250 *(int *)data = (tp->t_linesw == NULL) ? 251 2 /* XXX old NTTYDISC */ : tp->t_linesw->l_no; 252 mutex_spin_exit(&tty_lock); 253 break; 254 255 case OTIOCSETD: { 256 int ldisczero = 0; 257 258 return (ttioctl(tp, TIOCSETD, 259 *(int *)data == 2 ? (void *)&ldisczero : data, flag, 260 l)); 261 } 262 263 case OTIOCCONS: 264 *(int *)data = 1; 265 return (ttioctl(tp, TIOCCONS, data, flag, l)); 266 267 case TIOCHPCL: 268 mutex_spin_enter(&tty_lock); 269 SET(tp->t_cflag, HUPCL); 270 mutex_spin_exit(&tty_lock); 271 break; 272 273 case TIOCGSID: 274 mutex_enter(proc_lock); 275 if (tp->t_session == NULL) { 276 mutex_exit(proc_lock); 277 return ENOTTY; 278 } 279 if (tp->t_session->s_leader == NULL) { 280 mutex_exit(proc_lock); 281 return ENOTTY; 282 } 283 *(int *) data = tp->t_session->s_leader->p_pid; 284 mutex_exit(proc_lock); 285 break; 286 287 default: 288 return (EPASSTHROUGH); 289 } 290 return (0); 291 } 292 293 static int 294 ttcompatgetflags(struct tty *tp) 295 { 296 tcflag_t iflag = tp->t_iflag; 297 tcflag_t lflag = tp->t_lflag; 298 tcflag_t oflag = tp->t_oflag; 299 tcflag_t cflag = tp->t_cflag; 300 int flags = 0; 301 302 KASSERT(mutex_owned(&tty_lock)); 303 304 if (ISSET(iflag, IXOFF)) 305 SET(flags, TANDEM); 306 if (ISSET(iflag, ICRNL) || ISSET(oflag, ONLCR)) 307 SET(flags, CRMOD); 308 if (ISSET(cflag, PARENB)) { 309 if (ISSET(iflag, INPCK)) { 310 if (ISSET(cflag, PARODD)) 311 SET(flags, ODDP); 312 else 313 SET(flags, EVENP); 314 } else 315 SET(flags, ANYP); 316 } 317 318 if (!ISSET(lflag, ICANON)) { 319 /* fudge */ 320 if (ISSET(iflag, IXON) || ISSET(lflag, ISIG|IEXTEN) || 321 ISSET(cflag, PARENB)) 322 SET(flags, CBREAK); 323 else 324 SET(flags, RAW); 325 } 326 327 if (ISSET(flags, RAW)) 328 SET(flags, ISSET(tp->t_flags, LITOUT|PASS8)); 329 else if (ISSET(cflag, CSIZE) == CS8) { 330 if (!ISSET(oflag, OPOST)) 331 SET(flags, LITOUT); 332 if (!ISSET(iflag, ISTRIP)) 333 SET(flags, PASS8); 334 } 335 336 if (ISSET(cflag, MDMBUF)) 337 SET(flags, MDMBUF); 338 if (!ISSET(cflag, HUPCL)) 339 SET(flags, NOHANG); 340 if (ISSET(oflag, OXTABS)) 341 SET(flags, XTABS); 342 if (ISSET(lflag, ECHOE)) 343 SET(flags, CRTERA|CRTBS); 344 if (ISSET(lflag, ECHOKE)) 345 SET(flags, CRTKIL|CRTBS); 346 if (ISSET(lflag, ECHOPRT)) 347 SET(flags, PRTERA); 348 if (ISSET(lflag, ECHOCTL)) 349 SET(flags, CTLECH); 350 if (!ISSET(iflag, IXANY)) 351 SET(flags, DECCTQ); 352 SET(flags, ISSET(lflag, ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH)); 353 if (ttydebug) 354 printf("getflags: %x\n", flags); 355 return (flags); 356 } 357 358 static void 359 ttcompatsetflags(struct tty *tp, struct termios *t) 360 { 361 int flags = tp->t_flags; 362 363 KASSERT(mutex_owned(&tty_lock)); 364 365 tcflag_t iflag = t->c_iflag; 366 tcflag_t oflag = t->c_oflag; 367 tcflag_t lflag = t->c_lflag; 368 tcflag_t cflag = t->c_cflag; 369 370 if (ISSET(flags, TANDEM)) 371 SET(iflag, IXOFF); 372 else 373 CLR(iflag, IXOFF); 374 if (ISSET(flags, ECHO)) 375 SET(lflag, ECHO); 376 else 377 CLR(lflag, ECHO); 378 if (ISSET(flags, CRMOD)) { 379 SET(iflag, ICRNL); 380 SET(oflag, ONLCR); 381 } else { 382 CLR(iflag, ICRNL); 383 CLR(oflag, ONLCR); 384 } 385 if (ISSET(flags, XTABS)) 386 SET(oflag, OXTABS); 387 else 388 CLR(oflag, OXTABS); 389 390 391 if (ISSET(flags, RAW)) { 392 iflag &= IXOFF; 393 CLR(lflag, ISIG|ICANON|IEXTEN); 394 CLR(cflag, PARENB); 395 } else { 396 SET(iflag, BRKINT|IXON|IMAXBEL); 397 SET(lflag, ISIG|IEXTEN); 398 if (ISSET(flags, CBREAK)) 399 CLR(lflag, ICANON); 400 else 401 SET(lflag, ICANON); 402 switch (ISSET(flags, ANYP)) { 403 case 0: 404 CLR(cflag, PARENB); 405 break; 406 case ANYP: 407 SET(cflag, PARENB); 408 CLR(iflag, INPCK); 409 break; 410 case EVENP: 411 SET(cflag, PARENB); 412 SET(iflag, INPCK); 413 CLR(cflag, PARODD); 414 break; 415 case ODDP: 416 SET(cflag, PARENB); 417 SET(iflag, INPCK); 418 SET(cflag, PARODD); 419 break; 420 } 421 } 422 423 if (ISSET(flags, RAW|LITOUT|PASS8)) { 424 CLR(cflag, CSIZE); 425 SET(cflag, CS8); 426 if (!ISSET(flags, RAW|PASS8)) 427 SET(iflag, ISTRIP); 428 else 429 CLR(iflag, ISTRIP); 430 if (!ISSET(flags, RAW|LITOUT)) 431 SET(oflag, OPOST); 432 else 433 CLR(oflag, OPOST); 434 } else { 435 CLR(cflag, CSIZE); 436 SET(cflag, CS7); 437 SET(iflag, ISTRIP); 438 SET(oflag, OPOST); 439 } 440 441 t->c_iflag = iflag; 442 t->c_oflag = oflag; 443 t->c_lflag = lflag; 444 t->c_cflag = cflag; 445 } 446 447 static void 448 ttcompatsetlflags(struct tty *tp, struct termios *t) 449 { 450 int flags = tp->t_flags; 451 tcflag_t iflag = t->c_iflag; 452 tcflag_t oflag = t->c_oflag; 453 tcflag_t lflag = t->c_lflag; 454 tcflag_t cflag = t->c_cflag; 455 456 KASSERT(mutex_owned(&tty_lock)); 457 458 /* Nothing we can do with CRTBS. */ 459 if (ISSET(flags, PRTERA)) 460 SET(lflag, ECHOPRT); 461 else 462 CLR(lflag, ECHOPRT); 463 if (ISSET(flags, CRTERA)) 464 SET(lflag, ECHOE); 465 else 466 CLR(lflag, ECHOE); 467 /* Nothing we can do with TILDE. */ 468 if (ISSET(flags, MDMBUF)) 469 SET(cflag, MDMBUF); 470 else 471 CLR(cflag, MDMBUF); 472 if (ISSET(flags, NOHANG)) 473 CLR(cflag, HUPCL); 474 else 475 SET(cflag, HUPCL); 476 if (ISSET(flags, CRTKIL)) 477 SET(lflag, ECHOKE); 478 else 479 CLR(lflag, ECHOKE); 480 if (ISSET(flags, CTLECH)) 481 SET(lflag, ECHOCTL); 482 else 483 CLR(lflag, ECHOCTL); 484 if (!ISSET(flags, DECCTQ)) 485 SET(iflag, IXANY); 486 else 487 CLR(iflag, IXANY); 488 CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH); 489 SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH)); 490 491 if (ISSET(flags, RAW|LITOUT|PASS8)) { 492 CLR(cflag, CSIZE); 493 SET(cflag, CS8); 494 if (!ISSET(flags, RAW|PASS8)) 495 SET(iflag, ISTRIP); 496 else 497 CLR(iflag, ISTRIP); 498 if (!ISSET(flags, RAW|LITOUT)) 499 SET(oflag, OPOST); 500 else 501 CLR(oflag, OPOST); 502 } else { 503 CLR(cflag, CSIZE); 504 SET(cflag, CS7); 505 SET(iflag, ISTRIP); 506 SET(oflag, OPOST); 507 } 508 509 t->c_iflag = iflag; 510 t->c_oflag = oflag; 511 t->c_lflag = lflag; 512 t->c_cflag = cflag; 513 } 514