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