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