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