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 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#)tty_compat.c 8.1 (Berkeley) 6/10/93 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include "opt_compat.h" 36 37 /* 38 * mapping routines for old line discipline (yuck) 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/ioctl_compat.h> 44 #include <sys/tty.h> 45 #include <sys/kernel.h> 46 #include <sys/sysctl.h> 47 48 struct speedtab { 49 int sp_speed; /* Speed. */ 50 int sp_code; /* Code. */ 51 }; 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(int speed, struct speedtab *table) 90 { 91 if (speed == 0) 92 return (0); /* hangup */ 93 for ( ; table->sp_speed > 0; table++) 94 if (table->sp_speed <= speed) /* nearest one, rounded down */ 95 return (table->sp_code); 96 return (1); /* 50, min and not hangup */ 97 } 98 99 static int 100 ttsetcompat(struct tty *tp, u_long *com, caddr_t data, struct termios *term) 101 { 102 switch (*com) { 103 case TIOCSETP: 104 case TIOCSETN: { 105 struct sgttyb *sg = (struct sgttyb *)data; 106 int speed; 107 108 if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0) 109 return(EINVAL); 110 else if (speed != ttcompatspeedtab(tp->t_termios.c_ispeed, 111 compatspeeds)) 112 term->c_ispeed = compatspcodes[speed]; 113 else 114 term->c_ispeed = tp->t_termios.c_ispeed; 115 if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0) 116 return(EINVAL); 117 else if (speed != ttcompatspeedtab(tp->t_termios.c_ospeed, 118 compatspeeds)) 119 term->c_ospeed = compatspcodes[speed]; 120 else 121 term->c_ospeed = tp->t_termios.c_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 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 == (char)_POSIX_VDISABLE) 141 cc[VEOL2] = _POSIX_VDISABLE; 142 *com = TIOCSETA; 143 break; 144 } 145 case TIOCSLTC: { 146 struct ltchars *ltc = (struct ltchars *)data; 147 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 tty_ioctl_compat(struct tty *tp, u_long com, caddr_t data, struct thread *td) 182 { 183 switch (com) { 184 case TIOCSETP: 185 case TIOCSETN: 186 case TIOCSETC: 187 case TIOCSLTC: 188 case TIOCLBIS: 189 case TIOCLBIC: 190 case TIOCLSET: { 191 struct termios term; 192 int error; 193 194 term = tp->t_termios; 195 if ((error = ttsetcompat(tp, &com, data, &term)) != 0) 196 return error; 197 return tty_ioctl(tp, com, &term, td); 198 } 199 case TIOCGETP: { 200 struct sgttyb *sg = (struct sgttyb *)data; 201 cc_t *cc = tp->t_termios.c_cc; 202 203 sg->sg_ospeed = ttcompatspeedtab(tp->t_termios.c_ospeed, 204 compatspeeds); 205 if (tp->t_termios.c_ispeed == 0) 206 sg->sg_ispeed = sg->sg_ospeed; 207 else 208 sg->sg_ispeed = ttcompatspeedtab(tp->t_termios.c_ispeed, 209 compatspeeds); 210 sg->sg_erase = cc[VERASE]; 211 sg->sg_kill = cc[VKILL]; 212 sg->sg_flags = tp->t_flags = ttcompatgetflags(tp); 213 break; 214 } 215 case TIOCGETC: { 216 struct tchars *tc = (struct tchars *)data; 217 cc_t *cc = tp->t_termios.c_cc; 218 219 tc->t_intrc = cc[VINTR]; 220 tc->t_quitc = cc[VQUIT]; 221 tc->t_startc = cc[VSTART]; 222 tc->t_stopc = cc[VSTOP]; 223 tc->t_eofc = cc[VEOF]; 224 tc->t_brkc = cc[VEOL]; 225 break; 226 } 227 case TIOCGLTC: { 228 struct ltchars *ltc = (struct ltchars *)data; 229 cc_t *cc = tp->t_termios.c_cc; 230 231 ltc->t_suspc = cc[VSUSP]; 232 ltc->t_dsuspc = cc[VDSUSP]; 233 ltc->t_rprntc = cc[VREPRINT]; 234 ltc->t_flushc = cc[VDISCARD]; 235 ltc->t_werasc = cc[VWERASE]; 236 ltc->t_lnextc = cc[VLNEXT]; 237 break; 238 } 239 case TIOCLGET: 240 tp->t_flags = 241 (ttcompatgetflags(tp) & 0xffff0000UL) 242 | (tp->t_flags & 0xffff); 243 *(int *)data = tp->t_flags>>16; 244 if (ttydebug) 245 printf("CLGET: returning %x\n", *(int *)data); 246 break; 247 248 case OTIOCGETD: 249 *(int *)data = 2; 250 break; 251 252 case OTIOCSETD: { 253 int ldisczero = 0; 254 255 return (tty_ioctl(tp, TIOCSETD, 256 *(int *)data == 2 ? (caddr_t)&ldisczero : data, td)); 257 } 258 259 case OTIOCCONS: 260 *(int *)data = 1; 261 return (tty_ioctl(tp, TIOCCONS, data, td)); 262 263 default: 264 return (ENOIOCTL); 265 } 266 return (0); 267 } 268 269 static int 270 ttcompatgetflags(struct tty *tp) 271 { 272 tcflag_t iflag = tp->t_termios.c_iflag; 273 tcflag_t lflag = tp->t_termios.c_lflag; 274 tcflag_t oflag = tp->t_termios.c_oflag; 275 tcflag_t cflag = tp->t_termios.c_cflag; 276 int flags = 0; 277 278 if (iflag&IXOFF) 279 flags |= TANDEM; 280 if (iflag&ICRNL || oflag&ONLCR) 281 flags |= CRMOD; 282 if ((cflag&CSIZE) == CS8) { 283 flags |= PASS8; 284 if (iflag&ISTRIP) 285 flags |= ANYP; 286 } 287 else if (cflag&PARENB) { 288 if (iflag&INPCK) { 289 if (cflag&PARODD) 290 flags |= ODDP; 291 else 292 flags |= EVENP; 293 } else 294 flags |= EVENP | ODDP; 295 } 296 297 if ((lflag&ICANON) == 0) { 298 /* fudge */ 299 if (iflag&(INPCK|ISTRIP|IXON) || lflag&(IEXTEN|ISIG) 300 || (cflag&(CSIZE|PARENB)) != CS8) 301 flags |= CBREAK; 302 else 303 flags |= RAW; 304 } 305 if (!(flags&RAW) && !(oflag&OPOST) && (cflag&(CSIZE|PARENB)) == CS8) 306 flags |= LITOUT; 307 if (cflag&MDMBUF) 308 flags |= MDMBUF; 309 if ((cflag&HUPCL) == 0) 310 flags |= NOHANG; 311 if (oflag&TAB3) 312 flags |= XTABS; 313 if (lflag&ECHOE) 314 flags |= CRTERA|CRTBS; 315 if (lflag&ECHOKE) 316 flags |= CRTKIL|CRTBS; 317 if (lflag&ECHOPRT) 318 flags |= PRTERA; 319 if (lflag&ECHOCTL) 320 flags |= CTLECH; 321 if ((iflag&IXANY) == 0) 322 flags |= DECCTQ; 323 flags |= lflag&(ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH); 324 if (ttydebug) 325 printf("getflags: %x\n", flags); 326 return (flags); 327 } 328 329 static void 330 ttcompatsetflags(struct tty *tp, struct termios *t) 331 { 332 int flags = tp->t_flags; 333 tcflag_t iflag = t->c_iflag; 334 tcflag_t oflag = t->c_oflag; 335 tcflag_t lflag = t->c_lflag; 336 tcflag_t cflag = t->c_cflag; 337 338 if (flags & RAW) { 339 iflag = IGNBRK; 340 lflag &= ~(ECHOCTL|ISIG|ICANON|IEXTEN); 341 } else { 342 iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR); 343 iflag |= BRKINT|IXON|IMAXBEL; 344 lflag |= ISIG|IEXTEN|ECHOCTL; /* XXX was echoctl on ? */ 345 if (flags & XTABS) 346 oflag |= TAB3; 347 else 348 oflag &= ~TAB3; 349 if (flags & CBREAK) 350 lflag &= ~ICANON; 351 else 352 lflag |= ICANON; 353 if (flags&CRMOD) { 354 iflag |= ICRNL; 355 oflag |= ONLCR; 356 } else { 357 iflag &= ~ICRNL; 358 oflag &= ~ONLCR; 359 } 360 } 361 if (flags&ECHO) 362 lflag |= ECHO; 363 else 364 lflag &= ~ECHO; 365 366 cflag &= ~(CSIZE|PARENB); 367 if (flags&(RAW|LITOUT|PASS8)) { 368 cflag |= CS8; 369 if (!(flags&(RAW|PASS8)) 370 || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP)) 371 iflag |= ISTRIP; 372 else 373 iflag &= ~ISTRIP; 374 if (flags&(RAW|LITOUT)) 375 oflag &= ~OPOST; 376 else 377 oflag |= OPOST; 378 } else { 379 cflag |= CS7|PARENB; 380 iflag |= ISTRIP; 381 oflag |= OPOST; 382 } 383 /* XXX don't set INPCK if RAW or PASS8? */ 384 if ((flags&(EVENP|ODDP)) == EVENP) { 385 iflag |= INPCK; 386 cflag &= ~PARODD; 387 } else if ((flags&(EVENP|ODDP)) == ODDP) { 388 iflag |= INPCK; 389 cflag |= PARODD; 390 } else 391 iflag &= ~INPCK; 392 if (flags&TANDEM) 393 iflag |= IXOFF; 394 else 395 iflag &= ~IXOFF; 396 if ((flags&DECCTQ) == 0) 397 iflag |= IXANY; 398 else 399 iflag &= ~IXANY; 400 t->c_iflag = iflag; 401 t->c_oflag = oflag; 402 t->c_lflag = lflag; 403 t->c_cflag = cflag; 404 } 405 406 static void 407 ttcompatsetlflags(struct tty *tp, struct termios *t) 408 { 409 int flags = tp->t_flags; 410 tcflag_t iflag = t->c_iflag; 411 tcflag_t oflag = t->c_oflag; 412 tcflag_t lflag = t->c_lflag; 413 tcflag_t cflag = t->c_cflag; 414 415 iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR); 416 if (flags&CRTERA) 417 lflag |= ECHOE; 418 else 419 lflag &= ~ECHOE; 420 if (flags&CRTKIL) 421 lflag |= ECHOKE; 422 else 423 lflag &= ~ECHOKE; 424 if (flags&PRTERA) 425 lflag |= ECHOPRT; 426 else 427 lflag &= ~ECHOPRT; 428 if (flags&CTLECH) 429 lflag |= ECHOCTL; 430 else 431 lflag &= ~ECHOCTL; 432 if (flags&TANDEM) 433 iflag |= IXOFF; 434 else 435 iflag &= ~IXOFF; 436 if ((flags&DECCTQ) == 0) 437 iflag |= IXANY; 438 else 439 iflag &= ~IXANY; 440 if (flags & MDMBUF) 441 cflag |= MDMBUF; 442 else 443 cflag &= ~MDMBUF; 444 if (flags&NOHANG) 445 cflag &= ~HUPCL; 446 else 447 cflag |= HUPCL; 448 lflag &= ~(TOSTOP|FLUSHO|PENDIN|NOFLSH); 449 lflag |= flags&(TOSTOP|FLUSHO|PENDIN|NOFLSH); 450 451 /* 452 * The next if-else statement is copied from above so don't bother 453 * checking it separately. We could avoid fiddlling with the 454 * character size if the mode is already RAW or if neither the 455 * LITOUT bit or the PASS8 bit is being changed, but the delta of 456 * the change is not available here and skipping the RAW case would 457 * make the code different from above. 458 */ 459 cflag &= ~(CSIZE|PARENB); 460 if (flags&(RAW|LITOUT|PASS8)) { 461 cflag |= CS8; 462 if (!(flags&(RAW|PASS8)) 463 || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP)) 464 iflag |= ISTRIP; 465 else 466 iflag &= ~ISTRIP; 467 if (flags&(RAW|LITOUT)) 468 oflag &= ~OPOST; 469 else 470 oflag |= OPOST; 471 } else { 472 cflag |= CS7|PARENB; 473 iflag |= ISTRIP; 474 oflag |= OPOST; 475 } 476 t->c_iflag = iflag; 477 t->c_oflag = oflag; 478 t->c_lflag = lflag; 479 t->c_cflag = cflag; 480 } 481