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