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.22 1997/03/24 12:03:03 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_compat.h> 45 #include <sys/tty.h> 46 #include <sys/kernel.h> 47 #include <sys/sysctl.h> 48 49 static int ttcompatgetflags __P((struct tty *tp)); 50 static void ttcompatsetflags __P((struct tty *tp, struct termios *t)); 51 static void ttcompatsetlflags __P((struct tty *tp, struct termios *t)); 52 static int ttcompatspeedtab __P((int speed, struct speedtab *table)); 53 54 static int ttydebug = 0; 55 SYSCTL_INT(_debug, OID_AUTO, ttydebug, CTLFLAG_RW, &ttydebug, 0, ""); 56 57 static struct speedtab compatspeeds[] = { 58 #define MAX_SPEED 17 59 { 115200, 17 }, 60 { 57600, 16 }, 61 { 38400, 15 }, 62 { 19200, 14 }, 63 { 9600, 13 }, 64 { 4800, 12 }, 65 { 2400, 11 }, 66 { 1800, 10 }, 67 { 1200, 9 }, 68 { 600, 8 }, 69 { 300, 7 }, 70 { 200, 6 }, 71 { 150, 5 }, 72 { 134, 4 }, 73 { 110, 3 }, 74 { 75, 2 }, 75 { 50, 1 }, 76 { 0, 0 }, 77 { -1, -1 }, 78 }; 79 static int compatspcodes[] = { 80 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 81 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 82 }; 83 84 static int 85 ttcompatspeedtab(speed, table) 86 int speed; 87 register struct speedtab *table; 88 { 89 if (speed == 0) 90 return (0); /* hangup */ 91 for ( ; table->sp_speed > 0; table++) 92 if (table->sp_speed <= speed) /* nearest one, rounded down */ 93 return (table->sp_code); 94 return (1); /* 50, min and not hangup */ 95 } 96 97 int 98 ttsetcompat(tp, com, data, term) 99 register struct tty *tp; 100 int *com; 101 caddr_t data; 102 struct termios *term; 103 { 104 switch (*com) { 105 case TIOCSETP: 106 case TIOCSETN: { 107 register struct sgttyb *sg = (struct sgttyb *)data; 108 int speed; 109 110 if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0) 111 return(EINVAL); 112 else if (speed != ttcompatspeedtab(tp->t_ispeed, compatspeeds)) 113 term->c_ispeed = compatspcodes[speed]; 114 else 115 term->c_ispeed = tp->t_ispeed; 116 if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0) 117 return(EINVAL); 118 else if (speed != ttcompatspeedtab(tp->t_ospeed, compatspeeds)) 119 term->c_ospeed = compatspcodes[speed]; 120 else 121 term->c_ospeed = tp->t_ospeed; 122 term->c_cc[VERASE] = sg->sg_erase; 123 term->c_cc[VKILL] = sg->sg_kill; 124 tp->t_flags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 125 ttcompatsetflags(tp, term); 126 *com = (*com == TIOCSETP) ? TIOCSETAF : TIOCSETA; 127 break; 128 } 129 case TIOCSETC: { 130 struct tchars *tc = (struct tchars *)data; 131 register cc_t *cc; 132 133 cc = term->c_cc; 134 cc[VINTR] = tc->t_intrc; 135 cc[VQUIT] = tc->t_quitc; 136 cc[VSTART] = tc->t_startc; 137 cc[VSTOP] = tc->t_stopc; 138 cc[VEOF] = tc->t_eofc; 139 cc[VEOL] = tc->t_brkc; 140 if (tc->t_brkc == -1) 141 cc[VEOL2] = _POSIX_VDISABLE; 142 *com = TIOCSETA; 143 break; 144 } 145 case TIOCSLTC: { 146 struct ltchars *ltc = (struct ltchars *)data; 147 register cc_t *cc; 148 149 cc = term->c_cc; 150 cc[VSUSP] = ltc->t_suspc; 151 cc[VDSUSP] = ltc->t_dsuspc; 152 cc[VREPRINT] = ltc->t_rprntc; 153 cc[VDISCARD] = ltc->t_flushc; 154 cc[VWERASE] = ltc->t_werasc; 155 cc[VLNEXT] = ltc->t_lnextc; 156 *com = TIOCSETA; 157 break; 158 } 159 case TIOCLBIS: 160 case TIOCLBIC: 161 case TIOCLSET: 162 if (*com == TIOCLSET) 163 tp->t_flags = (tp->t_flags&0xffff) | *(int *)data<<16; 164 else { 165 tp->t_flags = 166 (ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff); 167 if (*com == TIOCLBIS) 168 tp->t_flags |= *(int *)data<<16; 169 else 170 tp->t_flags &= ~(*(int *)data<<16); 171 } 172 ttcompatsetlflags(tp, term); 173 *com = TIOCSETA; 174 break; 175 } 176 return 0; 177 } 178 179 /*ARGSUSED*/ 180 int 181 ttcompat(tp, com, data, flag) 182 register struct tty *tp; 183 int com; 184 caddr_t data; 185 int flag; 186 { 187 switch (com) { 188 case TIOCSETP: 189 case TIOCSETN: 190 case TIOCSETC: 191 case TIOCSLTC: 192 case TIOCLBIS: 193 case TIOCLBIC: 194 case TIOCLSET: { 195 struct termios term; 196 int error; 197 198 term = tp->t_termios; 199 if ((error = ttsetcompat(tp, &com, data, &term)) != 0) 200 return error; 201 return ttioctl(tp, com, &term, flag); 202 } 203 case TIOCGETP: { 204 register struct sgttyb *sg = (struct sgttyb *)data; 205 register cc_t *cc = tp->t_cc; 206 207 sg->sg_ospeed = ttcompatspeedtab(tp->t_ospeed, compatspeeds); 208 if (tp->t_ispeed == 0) 209 sg->sg_ispeed = sg->sg_ospeed; 210 else 211 sg->sg_ispeed = ttcompatspeedtab(tp->t_ispeed, compatspeeds); 212 sg->sg_erase = cc[VERASE]; 213 sg->sg_kill = cc[VKILL]; 214 sg->sg_flags = tp->t_flags = ttcompatgetflags(tp); 215 break; 216 } 217 case TIOCGETC: { 218 struct tchars *tc = (struct tchars *)data; 219 register cc_t *cc = tp->t_cc; 220 221 tc->t_intrc = cc[VINTR]; 222 tc->t_quitc = cc[VQUIT]; 223 tc->t_startc = cc[VSTART]; 224 tc->t_stopc = cc[VSTOP]; 225 tc->t_eofc = cc[VEOF]; 226 tc->t_brkc = cc[VEOL]; 227 break; 228 } 229 case TIOCGLTC: { 230 struct ltchars *ltc = (struct ltchars *)data; 231 register cc_t *cc = tp->t_cc; 232 233 ltc->t_suspc = cc[VSUSP]; 234 ltc->t_dsuspc = cc[VDSUSP]; 235 ltc->t_rprntc = cc[VREPRINT]; 236 ltc->t_flushc = cc[VDISCARD]; 237 ltc->t_werasc = cc[VWERASE]; 238 ltc->t_lnextc = cc[VLNEXT]; 239 break; 240 } 241 case TIOCLGET: 242 tp->t_flags = 243 (ttcompatgetflags(tp) & 0xffff0000UL) 244 | (tp->t_flags & 0xffff); 245 *(int *)data = tp->t_flags>>16; 246 if (ttydebug) 247 printf("CLGET: returning %x\n", *(int *)data); 248 break; 249 250 case OTIOCGETD: 251 *(int *)data = tp->t_line ? tp->t_line : 2; 252 break; 253 254 case OTIOCSETD: { 255 int ldisczero = 0; 256 257 return (ttioctl(tp, TIOCSETD, 258 *(int *)data == 2 ? (caddr_t)&ldisczero : data, flag)); 259 } 260 261 case OTIOCCONS: 262 *(int *)data = 1; 263 return (ttioctl(tp, TIOCCONS, data, flag)); 264 265 default: 266 return (-1); 267 } 268 return (0); 269 } 270 271 static int 272 ttcompatgetflags(tp) 273 register struct tty *tp; 274 { 275 register tcflag_t iflag = tp->t_iflag; 276 register tcflag_t lflag = tp->t_lflag; 277 register tcflag_t oflag = tp->t_oflag; 278 register tcflag_t cflag = tp->t_cflag; 279 register flags = 0; 280 281 if (iflag&IXOFF) 282 flags |= TANDEM; 283 if (iflag&ICRNL || oflag&ONLCR) 284 flags |= CRMOD; 285 if ((cflag&CSIZE) == CS8) { 286 flags |= PASS8; 287 if (iflag&ISTRIP) 288 flags |= ANYP; 289 } 290 else if (cflag&PARENB) { 291 if (iflag&INPCK) { 292 if (cflag&PARODD) 293 flags |= ODDP; 294 else 295 flags |= EVENP; 296 } else 297 flags |= EVENP | ODDP; 298 } 299 300 if ((lflag&ICANON) == 0) { 301 /* fudge */ 302 if (iflag&(INPCK|ISTRIP|IXON) || lflag&(IEXTEN|ISIG) 303 || cflag&(CSIZE|PARENB) != CS8) 304 flags |= CBREAK; 305 else 306 flags |= RAW; 307 } 308 if (!(flags&RAW) && !(oflag&OPOST) && cflag&(CSIZE|PARENB) == CS8) 309 flags |= LITOUT; 310 if (cflag&MDMBUF) 311 flags |= MDMBUF; 312 if ((cflag&HUPCL) == 0) 313 flags |= NOHANG; 314 if (oflag&OXTABS) 315 flags |= XTABS; 316 if (lflag&ECHOE) 317 flags |= CRTERA|CRTBS; 318 if (lflag&ECHOKE) 319 flags |= CRTKIL|CRTBS; 320 if (lflag&ECHOPRT) 321 flags |= PRTERA; 322 if (lflag&ECHOCTL) 323 flags |= CTLECH; 324 if ((iflag&IXANY) == 0) 325 flags |= DECCTQ; 326 flags |= lflag&(ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH); 327 if (ttydebug) 328 printf("getflags: %x\n", flags); 329 return (flags); 330 } 331 332 static void 333 ttcompatsetflags(tp, t) 334 register struct tty *tp; 335 register struct termios *t; 336 { 337 register flags = tp->t_flags; 338 register tcflag_t iflag = t->c_iflag; 339 register tcflag_t oflag = t->c_oflag; 340 register tcflag_t lflag = t->c_lflag; 341 register tcflag_t cflag = t->c_cflag; 342 343 if (flags & RAW) { 344 iflag = IGNBRK; 345 lflag &= ~(ECHOCTL|ISIG|ICANON|IEXTEN); 346 } else { 347 iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR); 348 iflag |= BRKINT|IXON|IMAXBEL; 349 lflag |= ISIG|IEXTEN|ECHOCTL; /* XXX was echoctl on ? */ 350 if (flags & XTABS) 351 oflag |= OXTABS; 352 else 353 oflag &= ~OXTABS; 354 if (flags & CBREAK) 355 lflag &= ~ICANON; 356 else 357 lflag |= ICANON; 358 if (flags&CRMOD) { 359 iflag |= ICRNL; 360 oflag |= ONLCR; 361 } else { 362 iflag &= ~ICRNL; 363 oflag &= ~ONLCR; 364 } 365 } 366 if (flags&ECHO) 367 lflag |= ECHO; 368 else 369 lflag &= ~ECHO; 370 371 cflag &= ~(CSIZE|PARENB); 372 if (flags&(RAW|LITOUT|PASS8)) { 373 cflag |= CS8; 374 if (!(flags&(RAW|PASS8)) 375 || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP)) 376 iflag |= ISTRIP; 377 else 378 iflag &= ~ISTRIP; 379 if (flags&(RAW|LITOUT)) 380 oflag &= ~OPOST; 381 else 382 oflag |= OPOST; 383 } else { 384 cflag |= CS7|PARENB; 385 iflag |= ISTRIP; 386 oflag |= OPOST; 387 } 388 /* XXX don't set INPCK if RAW or PASS8? */ 389 if ((flags&(EVENP|ODDP)) == EVENP) { 390 iflag |= INPCK; 391 cflag &= ~PARODD; 392 } else if ((flags&(EVENP|ODDP)) == ODDP) { 393 iflag |= INPCK; 394 cflag |= PARODD; 395 } else 396 iflag &= ~INPCK; 397 if (flags&TANDEM) 398 iflag |= IXOFF; 399 else 400 iflag &= ~IXOFF; 401 if ((flags&DECCTQ) == 0) 402 iflag |= IXANY; 403 else 404 iflag &= ~IXANY; 405 t->c_iflag = iflag; 406 t->c_oflag = oflag; 407 t->c_lflag = lflag; 408 t->c_cflag = cflag; 409 } 410 411 static void 412 ttcompatsetlflags(tp, t) 413 register struct tty *tp; 414 register struct termios *t; 415 { 416 register flags = tp->t_flags; 417 register tcflag_t iflag = t->c_iflag; 418 register tcflag_t oflag = t->c_oflag; 419 register tcflag_t lflag = t->c_lflag; 420 register tcflag_t cflag = t->c_cflag; 421 422 iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR); 423 if (flags&CRTERA) 424 lflag |= ECHOE; 425 else 426 lflag &= ~ECHOE; 427 if (flags&CRTKIL) 428 lflag |= ECHOKE; 429 else 430 lflag &= ~ECHOKE; 431 if (flags&PRTERA) 432 lflag |= ECHOPRT; 433 else 434 lflag &= ~ECHOPRT; 435 if (flags&CTLECH) 436 lflag |= ECHOCTL; 437 else 438 lflag &= ~ECHOCTL; 439 if (flags&TANDEM) 440 iflag |= IXOFF; 441 else 442 iflag &= ~IXOFF; 443 if ((flags&DECCTQ) == 0) 444 iflag |= IXANY; 445 else 446 iflag &= ~IXANY; 447 if (flags & MDMBUF) 448 cflag |= MDMBUF; 449 else 450 cflag &= ~MDMBUF; 451 if (flags&NOHANG) 452 cflag &= ~HUPCL; 453 else 454 cflag |= HUPCL; 455 lflag &= ~(TOSTOP|FLUSHO|PENDIN|NOFLSH); 456 lflag |= flags&(TOSTOP|FLUSHO|PENDIN|NOFLSH); 457 458 /* 459 * The next if-else statement is copied from above so don't bother 460 * checking it separately. We could avoid fiddlling with the 461 * character size if the mode is already RAW or if neither the 462 * LITOUT bit or the PASS8 bit is being changed, but the delta of 463 * the change is not available here and skipping the RAW case would 464 * make the code different from above. 465 */ 466 cflag &= ~(CSIZE|PARENB); 467 if (flags&(RAW|LITOUT|PASS8)) { 468 cflag |= CS8; 469 if (!(flags&(RAW|PASS8)) 470 || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP)) 471 iflag |= ISTRIP; 472 else 473 iflag &= ~ISTRIP; 474 if (flags&(RAW|LITOUT)) 475 oflag &= ~OPOST; 476 else 477 oflag |= OPOST; 478 } else { 479 cflag |= CS7|PARENB; 480 iflag |= ISTRIP; 481 oflag |= OPOST; 482 } 483 t->c_iflag = iflag; 484 t->c_oflag = oflag; 485 t->c_lflag = lflag; 486 t->c_cflag = cflag; 487 } 488 #endif /* COMPAT_43 || COMPAT_SUNOS */ 489