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