1 /* $NetBSD: tty_43.c,v 1.27 2008/04/28 20:23:41 martin 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.27 2008/04/28 20:23:41 martin 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 /* 80 * XXX libcompat files should be included with config attributes 81 */ 82 #ifdef COMPAT_OLDTTY 83 84 int ttydebug = 0; 85 86 static const struct speedtab compatspeeds[] = { 87 #define MAX_SPEED 17 88 { 115200, 17 }, 89 { 57600, 16 }, 90 { 38400, 15 }, 91 { 19200, 14 }, 92 { 9600, 13 }, 93 { 4800, 12 }, 94 { 2400, 11 }, 95 { 1800, 10 }, 96 { 1200, 9 }, 97 { 600, 8 }, 98 { 300, 7 }, 99 { 200, 6 }, 100 { 150, 5 }, 101 { 134, 4 }, 102 { 110, 3 }, 103 { 75, 2 }, 104 { 50, 1 }, 105 { 0, 0 }, 106 { -1, -1 }, 107 }; 108 static const int compatspcodes[] = { 109 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 110 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200 111 }; 112 113 static int ttcompatgetflags(struct tty *); 114 static void ttcompatsetflags(struct tty *, struct termios *); 115 static void ttcompatsetlflags(struct tty *, struct termios *); 116 117 /*ARGSUSED*/ 118 int 119 ttcompat(struct tty *tp, u_long com, void *data, int flag, struct lwp *l) 120 { 121 122 switch (com) { 123 case TIOCGETP: { 124 struct sgttyb *sg = (struct sgttyb *)data; 125 u_char *cc; 126 int speed; 127 128 mutex_spin_enter(&tty_lock); 129 cc = tp->t_cc; 130 speed = ttspeedtab(tp->t_ospeed, compatspeeds); 131 sg->sg_ospeed = (speed == -1) ? MAX_SPEED : speed; 132 if (tp->t_ispeed == 0) 133 sg->sg_ispeed = sg->sg_ospeed; 134 else { 135 speed = ttspeedtab(tp->t_ispeed, compatspeeds); 136 sg->sg_ispeed = (speed == -1) ? MAX_SPEED : speed; 137 } 138 sg->sg_erase = cc[VERASE]; 139 sg->sg_kill = cc[VKILL]; 140 sg->sg_flags = ttcompatgetflags(tp); 141 mutex_spin_exit(&tty_lock); 142 break; 143 } 144 145 case TIOCSETP: 146 case TIOCSETN: { 147 struct sgttyb *sg = (struct sgttyb *)data; 148 struct termios term; 149 int speed; 150 151 mutex_spin_enter(&tty_lock); 152 term = tp->t_termios; 153 if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0) 154 term.c_ispeed = speed; 155 else 156 term.c_ispeed = compatspcodes[speed]; 157 if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0) 158 term.c_ospeed = speed; 159 else 160 term.c_ospeed = compatspcodes[speed]; 161 term.c_cc[VERASE] = sg->sg_erase; 162 term.c_cc[VKILL] = sg->sg_kill; 163 tp->t_flags = (ttcompatgetflags(tp)&0xffff0000) | (sg->sg_flags&0xffff); 164 ttcompatsetflags(tp, &term); 165 mutex_spin_exit(&tty_lock); 166 return (ttioctl(tp, com == TIOCSETP ? TIOCSETAF : TIOCSETA, 167 (void *)&term, flag, l)); 168 } 169 170 case TIOCGETC: { 171 struct tchars *tc = (struct tchars *)data; 172 u_char *cc = tp->t_cc; 173 174 tc->t_intrc = cc[VINTR]; 175 tc->t_quitc = cc[VQUIT]; 176 tc->t_startc = cc[VSTART]; 177 tc->t_stopc = cc[VSTOP]; 178 tc->t_eofc = cc[VEOF]; 179 tc->t_brkc = cc[VEOL]; 180 break; 181 } 182 case TIOCSETC: { 183 struct tchars *tc = (struct tchars *)data; 184 u_char *cc = tp->t_cc; 185 186 cc[VINTR] = tc->t_intrc; 187 cc[VQUIT] = tc->t_quitc; 188 cc[VSTART] = tc->t_startc; 189 cc[VSTOP] = tc->t_stopc; 190 cc[VEOF] = tc->t_eofc; 191 cc[VEOL] = tc->t_brkc; 192 if (tc->t_brkc == (char)-1) 193 cc[VEOL2] = _POSIX_VDISABLE; 194 break; 195 } 196 case TIOCSLTC: { 197 struct ltchars *ltc = (struct ltchars *)data; 198 u_char *cc = tp->t_cc; 199 200 cc[VSUSP] = ltc->t_suspc; 201 cc[VDSUSP] = ltc->t_dsuspc; 202 cc[VREPRINT] = ltc->t_rprntc; 203 cc[VDISCARD] = ltc->t_flushc; 204 cc[VWERASE] = ltc->t_werasc; 205 cc[VLNEXT] = ltc->t_lnextc; 206 break; 207 } 208 case TIOCGLTC: { 209 struct ltchars *ltc = (struct ltchars *)data; 210 u_char *cc = tp->t_cc; 211 212 ltc->t_suspc = cc[VSUSP]; 213 ltc->t_dsuspc = cc[VDSUSP]; 214 ltc->t_rprntc = cc[VREPRINT]; 215 ltc->t_flushc = cc[VDISCARD]; 216 ltc->t_werasc = cc[VWERASE]; 217 ltc->t_lnextc = cc[VLNEXT]; 218 break; 219 } 220 case TIOCLBIS: 221 case TIOCLBIC: 222 case TIOCLSET: { 223 struct termios term; 224 int flags; 225 226 mutex_spin_enter(&tty_lock); 227 term = tp->t_termios; 228 flags = ttcompatgetflags(tp); 229 switch (com) { 230 case TIOCLSET: 231 tp->t_flags = (flags&0xffff) | (*(int *)data<<16); 232 break; 233 case TIOCLBIS: 234 tp->t_flags = flags | (*(int *)data<<16); 235 break; 236 case TIOCLBIC: 237 tp->t_flags = flags & ~(*(int *)data<<16); 238 break; 239 } 240 ttcompatsetlflags(tp, &term); 241 mutex_spin_exit(&tty_lock); 242 return (ttioctl(tp, TIOCSETA, (void *)&term, flag, l)); 243 } 244 case TIOCLGET: 245 mutex_spin_enter(&tty_lock); 246 *(int *)data = ttcompatgetflags(tp)>>16; 247 mutex_spin_exit(&tty_lock); 248 if (ttydebug) 249 printf("CLGET: returning %x\n", *(int *)data); 250 break; 251 252 case OTIOCGETD: 253 mutex_spin_enter(&tty_lock); 254 *(int *)data = (tp->t_linesw == NULL) ? 255 2 /* XXX old NTTYDISC */ : tp->t_linesw->l_no; 256 mutex_spin_exit(&tty_lock); 257 break; 258 259 case OTIOCSETD: { 260 int ldisczero = 0; 261 262 return (ttioctl(tp, TIOCSETD, 263 *(int *)data == 2 ? (void *)&ldisczero : data, flag, 264 l)); 265 } 266 267 case OTIOCCONS: 268 *(int *)data = 1; 269 return (ttioctl(tp, TIOCCONS, data, flag, l)); 270 271 case TIOCHPCL: 272 mutex_spin_enter(&tty_lock); 273 SET(tp->t_cflag, HUPCL); 274 mutex_spin_exit(&tty_lock); 275 break; 276 277 case TIOCGSID: 278 mutex_enter(proc_lock); 279 if (tp->t_session == NULL) { 280 mutex_exit(proc_lock); 281 return ENOTTY; 282 } 283 if (tp->t_session->s_leader == NULL) { 284 mutex_exit(proc_lock); 285 return ENOTTY; 286 } 287 *(int *) data = tp->t_session->s_leader->p_pid; 288 mutex_exit(proc_lock); 289 break; 290 291 default: 292 return (EPASSTHROUGH); 293 } 294 return (0); 295 } 296 297 static int 298 ttcompatgetflags(struct tty *tp) 299 { 300 tcflag_t iflag = tp->t_iflag; 301 tcflag_t lflag = tp->t_lflag; 302 tcflag_t oflag = tp->t_oflag; 303 tcflag_t cflag = tp->t_cflag; 304 int flags = 0; 305 306 KASSERT(mutex_owned(&tty_lock)); 307 308 if (ISSET(iflag, IXOFF)) 309 SET(flags, TANDEM); 310 if (ISSET(iflag, ICRNL) || ISSET(oflag, ONLCR)) 311 SET(flags, CRMOD); 312 if (ISSET(cflag, PARENB)) { 313 if (ISSET(iflag, INPCK)) { 314 if (ISSET(cflag, PARODD)) 315 SET(flags, ODDP); 316 else 317 SET(flags, EVENP); 318 } else 319 SET(flags, ANYP); 320 } 321 322 if (!ISSET(lflag, ICANON)) { 323 /* fudge */ 324 if (ISSET(iflag, IXON) || ISSET(lflag, ISIG|IEXTEN) || 325 ISSET(cflag, PARENB)) 326 SET(flags, CBREAK); 327 else 328 SET(flags, RAW); 329 } 330 331 if (ISSET(flags, RAW)) 332 SET(flags, ISSET(tp->t_flags, LITOUT|PASS8)); 333 else if (ISSET(cflag, CSIZE) == CS8) { 334 if (!ISSET(oflag, OPOST)) 335 SET(flags, LITOUT); 336 if (!ISSET(iflag, ISTRIP)) 337 SET(flags, PASS8); 338 } 339 340 if (ISSET(cflag, MDMBUF)) 341 SET(flags, MDMBUF); 342 if (!ISSET(cflag, HUPCL)) 343 SET(flags, NOHANG); 344 if (ISSET(oflag, OXTABS)) 345 SET(flags, XTABS); 346 if (ISSET(lflag, ECHOE)) 347 SET(flags, CRTERA|CRTBS); 348 if (ISSET(lflag, ECHOKE)) 349 SET(flags, CRTKIL|CRTBS); 350 if (ISSET(lflag, ECHOPRT)) 351 SET(flags, PRTERA); 352 if (ISSET(lflag, ECHOCTL)) 353 SET(flags, CTLECH); 354 if (!ISSET(iflag, IXANY)) 355 SET(flags, DECCTQ); 356 SET(flags, ISSET(lflag, ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH)); 357 if (ttydebug) 358 printf("getflags: %x\n", flags); 359 return (flags); 360 } 361 362 static void 363 ttcompatsetflags(struct tty *tp, struct termios *t) 364 { 365 int flags = tp->t_flags; 366 367 KASSERT(mutex_owned(&tty_lock)); 368 369 tcflag_t iflag = t->c_iflag; 370 tcflag_t oflag = t->c_oflag; 371 tcflag_t lflag = t->c_lflag; 372 tcflag_t cflag = t->c_cflag; 373 374 if (ISSET(flags, TANDEM)) 375 SET(iflag, IXOFF); 376 else 377 CLR(iflag, IXOFF); 378 if (ISSET(flags, ECHO)) 379 SET(lflag, ECHO); 380 else 381 CLR(lflag, ECHO); 382 if (ISSET(flags, CRMOD)) { 383 SET(iflag, ICRNL); 384 SET(oflag, ONLCR); 385 } else { 386 CLR(iflag, ICRNL); 387 CLR(oflag, ONLCR); 388 } 389 if (ISSET(flags, XTABS)) 390 SET(oflag, OXTABS); 391 else 392 CLR(oflag, OXTABS); 393 394 395 if (ISSET(flags, RAW)) { 396 iflag &= IXOFF; 397 CLR(lflag, ISIG|ICANON|IEXTEN); 398 CLR(cflag, PARENB); 399 } else { 400 SET(iflag, BRKINT|IXON|IMAXBEL); 401 SET(lflag, ISIG|IEXTEN); 402 if (ISSET(flags, CBREAK)) 403 CLR(lflag, ICANON); 404 else 405 SET(lflag, ICANON); 406 switch (ISSET(flags, ANYP)) { 407 case 0: 408 CLR(cflag, PARENB); 409 break; 410 case ANYP: 411 SET(cflag, PARENB); 412 CLR(iflag, INPCK); 413 break; 414 case EVENP: 415 SET(cflag, PARENB); 416 SET(iflag, INPCK); 417 CLR(cflag, PARODD); 418 break; 419 case ODDP: 420 SET(cflag, PARENB); 421 SET(iflag, INPCK); 422 SET(cflag, PARODD); 423 break; 424 } 425 } 426 427 if (ISSET(flags, RAW|LITOUT|PASS8)) { 428 CLR(cflag, CSIZE); 429 SET(cflag, CS8); 430 if (!ISSET(flags, RAW|PASS8)) 431 SET(iflag, ISTRIP); 432 else 433 CLR(iflag, ISTRIP); 434 if (!ISSET(flags, RAW|LITOUT)) 435 SET(oflag, OPOST); 436 else 437 CLR(oflag, OPOST); 438 } else { 439 CLR(cflag, CSIZE); 440 SET(cflag, CS7); 441 SET(iflag, ISTRIP); 442 SET(oflag, OPOST); 443 } 444 445 t->c_iflag = iflag; 446 t->c_oflag = oflag; 447 t->c_lflag = lflag; 448 t->c_cflag = cflag; 449 } 450 451 static void 452 ttcompatsetlflags(struct tty *tp, struct termios *t) 453 { 454 int flags = tp->t_flags; 455 tcflag_t iflag = t->c_iflag; 456 tcflag_t oflag = t->c_oflag; 457 tcflag_t lflag = t->c_lflag; 458 tcflag_t cflag = t->c_cflag; 459 460 KASSERT(mutex_owned(&tty_lock)); 461 462 /* Nothing we can do with CRTBS. */ 463 if (ISSET(flags, PRTERA)) 464 SET(lflag, ECHOPRT); 465 else 466 CLR(lflag, ECHOPRT); 467 if (ISSET(flags, CRTERA)) 468 SET(lflag, ECHOE); 469 else 470 CLR(lflag, ECHOE); 471 /* Nothing we can do with TILDE. */ 472 if (ISSET(flags, MDMBUF)) 473 SET(cflag, MDMBUF); 474 else 475 CLR(cflag, MDMBUF); 476 if (ISSET(flags, NOHANG)) 477 CLR(cflag, HUPCL); 478 else 479 SET(cflag, HUPCL); 480 if (ISSET(flags, CRTKIL)) 481 SET(lflag, ECHOKE); 482 else 483 CLR(lflag, ECHOKE); 484 if (ISSET(flags, CTLECH)) 485 SET(lflag, ECHOCTL); 486 else 487 CLR(lflag, ECHOCTL); 488 if (!ISSET(flags, DECCTQ)) 489 SET(iflag, IXANY); 490 else 491 CLR(iflag, IXANY); 492 CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH); 493 SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH)); 494 495 if (ISSET(flags, RAW|LITOUT|PASS8)) { 496 CLR(cflag, CSIZE); 497 SET(cflag, CS8); 498 if (!ISSET(flags, RAW|PASS8)) 499 SET(iflag, ISTRIP); 500 else 501 CLR(iflag, ISTRIP); 502 if (!ISSET(flags, RAW|LITOUT)) 503 SET(oflag, OPOST); 504 else 505 CLR(oflag, OPOST); 506 } else { 507 CLR(cflag, CSIZE); 508 SET(cflag, CS7); 509 SET(iflag, ISTRIP); 510 SET(oflag, OPOST); 511 } 512 513 t->c_iflag = iflag; 514 t->c_oflag = oflag; 515 t->c_lflag = lflag; 516 t->c_cflag = cflag; 517 } 518 519 #endif /* COMPAT_OLDTTY */ 520