tty_compat.c revision 154170
176259Sgreen/*- 276259Sgreen * Copyright (c) 1982, 1986, 1991, 1993 392555Sdes * The Regents of the University of California. All rights reserved. 476259Sgreen * 576259Sgreen * Redistribution and use in source and binary forms, with or without 676259Sgreen * modification, are permitted provided that the following conditions 776259Sgreen * are met: 876259Sgreen * 1. Redistributions of source code must retain the above copyright 976259Sgreen * notice, this list of conditions and the following disclaimer. 1076259Sgreen * 2. Redistributions in binary form must reproduce the above copyright 1176259Sgreen * notice, this list of conditions and the following disclaimer in the 1276259Sgreen * documentation and/or other materials provided with the distribution. 1376259Sgreen * 4. Neither the name of the University nor the names of its contributors 1476259Sgreen * may be used to endorse or promote products derived from this software 1576259Sgreen * without specific prior written permission. 1676259Sgreen * 1776259Sgreen * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1876259Sgreen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1976259Sgreen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2076259Sgreen * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2176259Sgreen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2276259Sgreen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2376259Sgreen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2476259Sgreen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2576259Sgreen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2698684Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2792876Sdes * SUCH DAMAGE. 2876259Sgreen * 2976259Sgreen * @(#)tty_compat.c 8.1 (Berkeley) 6/10/93 3076259Sgreen */ 3192555Sdes 3276259Sgreen#include <sys/cdefs.h> 3376259Sgreen__FBSDID("$FreeBSD: head/sys/kern/tty_compat.c 154170 2006-01-10 09:19:10Z phk $"); 3476259Sgreen 3592555Sdes#include "opt_compat.h" 3676259Sgreen 3776259Sgreen/* 3892555Sdes * mapping routines for old line discipline (yuck) 3992555Sdes */ 4092555Sdes 4176259Sgreen#include <sys/param.h> 4292555Sdes#include <sys/systm.h> 4392555Sdes#include <sys/ioctl_compat.h> 4492876Sdes#include <sys/tty.h> 4592876Sdes#include <sys/kernel.h> 4692876Sdes#include <sys/sysctl.h> 4792555Sdes 4892555Sdesstatic int ttcompatgetflags(struct tty *tp); 4992555Sdesstatic void ttcompatsetflags(struct tty *tp, struct termios *t); 5092555Sdesstatic void ttcompatsetlflags(struct tty *tp, struct termios *t); 5192555Sdesstatic int ttcompatspeedtab(int speed, struct speedtab *table); 5292555Sdes 5392876Sdesstatic int ttydebug = 0; 5492876SdesSYSCTL_INT(_debug, OID_AUTO, ttydebug, CTLFLAG_RW, &ttydebug, 0, ""); 5592876Sdes 5692555Sdesstatic struct speedtab compatspeeds[] = { 5792555Sdes#define MAX_SPEED 17 5892555Sdes { 115200, 17 }, 5992555Sdes { 57600, 16 }, 6092555Sdes { 38400, 15 }, 6192555Sdes { 19200, 14 }, 6292555Sdes { 9600, 13 }, 6392555Sdes { 4800, 12 }, 6492555Sdes { 2400, 11 }, 6592555Sdes { 1800, 10 }, 6692555Sdes { 1200, 9 }, 6792555Sdes { 600, 8 }, 6892555Sdes { 300, 7 }, 6992555Sdes { 200, 6 }, 7092555Sdes { 150, 5 }, 7192555Sdes { 134, 4 }, 7292555Sdes { 110, 3 }, 7392555Sdes { 75, 2 }, 7492555Sdes { 50, 1 }, 7592555Sdes { 0, 0 }, 7692555Sdes { -1, -1 }, 7792555Sdes}; 7892555Sdesstatic int compatspcodes[] = { 7992555Sdes 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 8092555Sdes 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 8192555Sdes}; 8292555Sdes 8392555Sdesstatic int 8492555Sdesttcompatspeedtab(int speed, struct speedtab *table) 8592555Sdes{ 8692555Sdes if (speed == 0) 8792555Sdes return (0); /* hangup */ 8892555Sdes for ( ; table->sp_speed > 0; table++) 8992555Sdes if (table->sp_speed <= speed) /* nearest one, rounded down */ 9092555Sdes return (table->sp_code); 9192555Sdes return (1); /* 50, min and not hangup */ 9292555Sdes} 9392555Sdes 9492555Sdesstatic int 9592555Sdesttsetcompat(struct tty *tp, u_long *com, caddr_t data, struct termios *term) 9692555Sdes{ 9792555Sdes switch (*com) { 9892555Sdes case TIOCSETP: 9992555Sdes case TIOCSETN: { 10092555Sdes struct sgttyb *sg = (struct sgttyb *)data; 10192555Sdes int speed; 10292555Sdes 10392555Sdes if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0) 10492555Sdes return(EINVAL); 10592555Sdes else if (speed != ttcompatspeedtab(tp->t_ispeed, compatspeeds)) 10692555Sdes term->c_ispeed = compatspcodes[speed]; 10792555Sdes else 10892555Sdes term->c_ispeed = tp->t_ispeed; 10992555Sdes if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0) 11092555Sdes return(EINVAL); 11192555Sdes else if (speed != ttcompatspeedtab(tp->t_ospeed, compatspeeds)) 11292555Sdes term->c_ospeed = compatspcodes[speed]; 11392555Sdes else 11492555Sdes term->c_ospeed = tp->t_ospeed; 11592555Sdes term->c_cc[VERASE] = sg->sg_erase; 11692555Sdes term->c_cc[VKILL] = sg->sg_kill; 11792555Sdes tp->t_flags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 11892555Sdes ttcompatsetflags(tp, term); 11992555Sdes *com = (*com == TIOCSETP) ? TIOCSETAF : TIOCSETA; 12092555Sdes break; 12192555Sdes } 12292555Sdes case TIOCSETC: { 12392555Sdes struct tchars *tc = (struct tchars *)data; 12492555Sdes cc_t *cc; 12592555Sdes 12692555Sdes cc = term->c_cc; 12792555Sdes cc[VINTR] = tc->t_intrc; 12892555Sdes cc[VQUIT] = tc->t_quitc; 12992555Sdes cc[VSTART] = tc->t_startc; 13092555Sdes cc[VSTOP] = tc->t_stopc; 13192555Sdes cc[VEOF] = tc->t_eofc; 13292555Sdes cc[VEOL] = tc->t_brkc; 13392555Sdes if (tc->t_brkc == (char)_POSIX_VDISABLE) 13492555Sdes cc[VEOL2] = _POSIX_VDISABLE; 13592555Sdes *com = TIOCSETA; 13692555Sdes break; 13792555Sdes } 13892555Sdes case TIOCSLTC: { 13992555Sdes struct ltchars *ltc = (struct ltchars *)data; 14092555Sdes cc_t *cc; 14192555Sdes 14292555Sdes cc = term->c_cc; 14392555Sdes cc[VSUSP] = ltc->t_suspc; 14492555Sdes cc[VDSUSP] = ltc->t_dsuspc; 14592555Sdes cc[VREPRINT] = ltc->t_rprntc; 14676259Sgreen cc[VDISCARD] = ltc->t_flushc; 14792555Sdes cc[VWERASE] = ltc->t_werasc; 14876259Sgreen cc[VLNEXT] = ltc->t_lnextc; 14976259Sgreen *com = TIOCSETA; 15076259Sgreen break; 15176259Sgreen } 15276259Sgreen case TIOCLBIS: 15392555Sdes case TIOCLBIC: 15492555Sdes case TIOCLSET: 15592555Sdes if (*com == TIOCLSET) 15676259Sgreen tp->t_flags = (tp->t_flags&0xffff) | *(int *)data<<16; 15792555Sdes else { 15876259Sgreen tp->t_flags = 15992555Sdes (ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff); 16092555Sdes if (*com == TIOCLBIS) 16192555Sdes tp->t_flags |= *(int *)data<<16; 16292555Sdes else 16392555Sdes tp->t_flags &= ~(*(int *)data<<16); 16492555Sdes } 16592555Sdes ttcompatsetlflags(tp, term); 16692555Sdes *com = TIOCSETA; 16792555Sdes break; 16892555Sdes } 16992555Sdes return 0; 17092555Sdes} 17192555Sdes 17292555Sdes/*ARGSUSED*/ 17392555Sdesint 17492555Sdesttcompat(struct tty *tp, u_long com, caddr_t data, int flag) 17592555Sdes{ 17692555Sdes switch (com) { 17792555Sdes case TIOCSETP: 17892555Sdes case TIOCSETN: 17992555Sdes case TIOCSETC: 18092555Sdes case TIOCSLTC: 18192555Sdes case TIOCLBIS: 18292555Sdes case TIOCLBIC: 18392555Sdes case TIOCLSET: { 18492555Sdes struct termios term; 18592555Sdes int error; 18692555Sdes 18776259Sgreen term = tp->t_termios; 18892555Sdes if ((error = ttsetcompat(tp, &com, data, &term)) != 0) 18992555Sdes return error; 19092555Sdes return ttioctl(tp, com, &term, flag); 19192555Sdes } 19292555Sdes case TIOCGETP: { 19392555Sdes struct sgttyb *sg = (struct sgttyb *)data; 19492555Sdes cc_t *cc = tp->t_cc; 19592555Sdes 19692555Sdes sg->sg_ospeed = ttcompatspeedtab(tp->t_ospeed, compatspeeds); 19792555Sdes if (tp->t_ispeed == 0) 19892555Sdes sg->sg_ispeed = sg->sg_ospeed; 19992555Sdes else 20076259Sgreen sg->sg_ispeed = ttcompatspeedtab(tp->t_ispeed, compatspeeds); 20176259Sgreen sg->sg_erase = cc[VERASE]; 20292555Sdes sg->sg_kill = cc[VKILL]; 20376259Sgreen sg->sg_flags = tp->t_flags = ttcompatgetflags(tp); 20476259Sgreen break; 20576259Sgreen } 20676259Sgreen case TIOCGETC: { 20792555Sdes struct tchars *tc = (struct tchars *)data; 20892555Sdes cc_t *cc = tp->t_cc; 20976259Sgreen 21092555Sdes tc->t_intrc = cc[VINTR]; 21192555Sdes tc->t_quitc = cc[VQUIT]; 21292555Sdes tc->t_startc = cc[VSTART]; 21392555Sdes tc->t_stopc = cc[VSTOP]; 21476259Sgreen tc->t_eofc = cc[VEOF]; 21592555Sdes tc->t_brkc = cc[VEOL]; 21692555Sdes break; 21792555Sdes } 21892555Sdes case TIOCGLTC: { 21992555Sdes struct ltchars *ltc = (struct ltchars *)data; 22076259Sgreen cc_t *cc = tp->t_cc; 22192555Sdes 22292555Sdes ltc->t_suspc = cc[VSUSP]; 22398684Sdes ltc->t_dsuspc = cc[VDSUSP]; 22492555Sdes ltc->t_rprntc = cc[VREPRINT]; 22592555Sdes ltc->t_flushc = cc[VDISCARD]; 22692555Sdes ltc->t_werasc = cc[VWERASE]; 22792555Sdes ltc->t_lnextc = cc[VLNEXT]; 22892555Sdes break; 22976259Sgreen } 23076259Sgreen case TIOCLGET: 23192555Sdes tp->t_flags = 23292555Sdes (ttcompatgetflags(tp) & 0xffff0000UL) 23392555Sdes | (tp->t_flags & 0xffff); 23492555Sdes *(int *)data = tp->t_flags>>16; 23592555Sdes if (ttydebug) 23692555Sdes printf("CLGET: returning %x\n", *(int *)data); 23792555Sdes break; 23892555Sdes 23976259Sgreen case OTIOCGETD: 24076259Sgreen *(int *)data = tp->t_line ? tp->t_line : 2; 24192555Sdes break; 24292555Sdes 24376259Sgreen case OTIOCSETD: { 24476259Sgreen int ldisczero = 0; 24592555Sdes 24692555Sdes return (ttioctl(tp, TIOCSETD, 24792555Sdes *(int *)data == 2 ? (caddr_t)&ldisczero : data, flag)); 24892555Sdes } 24976259Sgreen 25076259Sgreen case OTIOCCONS: 25176259Sgreen *(int *)data = 1; 25292555Sdes return (ttioctl(tp, TIOCCONS, data, flag)); 25392555Sdes 25492555Sdes default: 25592555Sdes return (ENOIOCTL); 25692555Sdes } 25776259Sgreen return (0); 25876259Sgreen} 25976259Sgreen 26092555Sdesstatic int 26192555Sdesttcompatgetflags(struct tty *tp) 26292555Sdes{ 26392555Sdes tcflag_t iflag = tp->t_iflag; 26492555Sdes tcflag_t lflag = tp->t_lflag; 26592555Sdes tcflag_t oflag = tp->t_oflag; 26692555Sdes tcflag_t cflag = tp->t_cflag; 26792555Sdes int flags = 0; 26892555Sdes 26992555Sdes if (iflag&IXOFF) 27092555Sdes flags |= TANDEM; 27192555Sdes if (iflag&ICRNL || oflag&ONLCR) 27292555Sdes flags |= CRMOD; 27392555Sdes if ((cflag&CSIZE) == CS8) { 27492555Sdes flags |= PASS8; 27592555Sdes if (iflag&ISTRIP) 27692555Sdes flags |= ANYP; 27792555Sdes } 27892555Sdes else if (cflag&PARENB) { 27976259Sgreen if (iflag&INPCK) { 28092555Sdes if (cflag&PARODD) 28192555Sdes flags |= ODDP; 28292555Sdes else 28392555Sdes flags |= EVENP; 28492555Sdes } else 28592555Sdes flags |= EVENP | ODDP; 28692555Sdes } 28792555Sdes 28892555Sdes if ((lflag&ICANON) == 0) { 28992555Sdes /* fudge */ 29092555Sdes if (iflag&(INPCK|ISTRIP|IXON) || lflag&(IEXTEN|ISIG) 29192555Sdes || (cflag&(CSIZE|PARENB)) != CS8) 29292555Sdes flags |= CBREAK; 29392555Sdes else 29476259Sgreen flags |= RAW; 29576259Sgreen } 29692555Sdes if (!(flags&RAW) && !(oflag&OPOST) && (cflag&(CSIZE|PARENB)) == CS8) 29792555Sdes flags |= LITOUT; 29892555Sdes if (cflag&MDMBUF) 29992555Sdes flags |= MDMBUF; 30092555Sdes if ((cflag&HUPCL) == 0) 30192555Sdes flags |= NOHANG; 30292555Sdes if (oflag&OXTABS) 30392555Sdes flags |= XTABS; 30492555Sdes if (lflag&ECHOE) 30592555Sdes flags |= CRTERA|CRTBS; 30692555Sdes if (lflag&ECHOKE) 30792555Sdes flags |= CRTKIL|CRTBS; 30892555Sdes if (lflag&ECHOPRT) 30992555Sdes flags |= PRTERA; 31092555Sdes if (lflag&ECHOCTL) 31176259Sgreen flags |= CTLECH; 31292555Sdes if ((iflag&IXANY) == 0) 31376259Sgreen flags |= DECCTQ; 31498684Sdes flags |= lflag&(ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH); 31598684Sdes if (ttydebug) 31698684Sdes printf("getflags: %x\n", flags); 31798684Sdes return (flags); 31898684Sdes} 31998684Sdes 32098684Sdesstatic void 32198684Sdesttcompatsetflags(struct tty *tp, struct termios *t) 32298684Sdes{ 32398684Sdes int flags = tp->t_flags; 32498684Sdes tcflag_t iflag = t->c_iflag; 32598684Sdes tcflag_t oflag = t->c_oflag; 32698684Sdes tcflag_t lflag = t->c_lflag; 32798684Sdes tcflag_t cflag = t->c_cflag; 32898684Sdes 32998684Sdes if (flags & RAW) { 33098684Sdes iflag = IGNBRK; 33198684Sdes lflag &= ~(ECHOCTL|ISIG|ICANON|IEXTEN); 33298684Sdes } 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 397static void 398ttcompatsetlflags(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