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