tty_compat.c revision 31577
159816Smdodd/*-
259816Smdodd * Copyright (c) 1982, 1986, 1991, 1993
359816Smdodd *	The Regents of the University of California.  All rights reserved.
459816Smdodd *
559816Smdodd * Redistribution and use in source and binary forms, with or without
659816Smdodd * modification, are permitted provided that the following conditions
759816Smdodd * are met:
859816Smdodd * 1. Redistributions of source code must retain the above copyright
959816Smdodd *    notice, this list of conditions and the following disclaimer.
1059816Smdodd * 2. Redistributions in binary form must reproduce the above copyright
1159816Smdodd *    notice, this list of conditions and the following disclaimer in the
1259816Smdodd *    documentation and/or other materials provided with the distribution.
1359816Smdodd * 3. All advertising materials mentioning features or use of this software
1459816Smdodd *    must display the following acknowledgement:
1559816Smdodd *	This product includes software developed by the University of
1659816Smdodd *	California, Berkeley and its contributors.
1759816Smdodd * 4. Neither the name of the University nor the names of its contributors
1859816Smdodd *    may be used to endorse or promote products derived from this software
1959816Smdodd *    without specific prior written permission.
2059816Smdodd *
2159816Smdodd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259816Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359816Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459816Smdodd * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559816Smdodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659816Smdodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759816Smdodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28119418Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29119418Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30119418Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159816Smdodd * SUCH DAMAGE.
3259816Smdodd *
3359816Smdodd *	@(#)tty_compat.c	8.1 (Berkeley) 6/10/93
3459816Smdodd * $Id: tty_compat.c,v 1.23 1997/08/02 14:31:39 bde Exp $
3559816Smdodd */
3659816Smdodd
3759816Smdodd/*
3859816Smdodd * mapping routines for old line discipline (yuck)
3959816Smdodd */
4059816Smdodd#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
4159816Smdodd
4259816Smdodd#include <sys/param.h>
4359816Smdodd#include <sys/systm.h>
4459816Smdodd#include <sys/ioctl_compat.h>
4559816Smdodd#include <sys/tty.h>
4659816Smdodd#include <sys/kernel.h>
4759816Smdodd#include <sys/sysctl.h>
4859816Smdodd
4959816Smdoddstatic int ttcompatgetflags	__P((struct tty	*tp));
5059816Smdoddstatic void ttcompatsetflags	__P((struct tty	*tp, struct termios *t));
5159816Smdoddstatic void ttcompatsetlflags	__P((struct tty	*tp, struct termios *t));
5259816Smdoddstatic int ttcompatspeedtab	__P((int speed, struct speedtab *table));
5359816Smdodd
5459816Smdoddstatic int ttydebug = 0;
55131192SimpSYSCTL_INT(_debug, OID_AUTO, ttydebug, CTLFLAG_RW, &ttydebug, 0, "");
56131192Simp
57131192Simpstatic struct speedtab compatspeeds[] = {
5859816Smdodd#define MAX_SPEED	17
59131192Simp	{ 115200, 17 },
60131192Simp	{ 57600, 16 },
6159816Smdodd	{ 38400, 15 },
62131192Simp	{ 19200, 14 },
6359816Smdodd	{ 9600,	13 },
6459816Smdodd	{ 4800,	12 },
6559816Smdodd	{ 2400,	11 },
6659816Smdodd	{ 1800,	10 },
67112801Smdodd	{ 1200,	9 },
6859816Smdodd	{ 600,	8 },
6959816Smdodd	{ 300,	7 },
7059816Smdodd	{ 200,	6 },
7159816Smdodd	{ 150,	5 },
72112800Smdodd	{ 134,	4 },
7359816Smdodd	{ 110,	3 },
7459816Smdodd	{ 75,	2 },
7559816Smdodd	{ 50,	1 },
7659816Smdodd	{ 0,	0 },
77112801Smdodd	{ -1,	-1 },
7859816Smdodd};
79112801Smdoddstatic int compatspcodes[] = {
8059816Smdodd	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
8159816Smdodd	1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200,
8259816Smdodd};
83112801Smdodd
8459816Smdoddstatic int
8559816Smdoddttcompatspeedtab(speed, table)
8659816Smdodd	int speed;
8759816Smdodd	register struct speedtab *table;
8859816Smdodd{
8959816Smdodd	if (speed == 0)
9059816Smdodd		return (0); /* hangup */
9159816Smdodd	for ( ; table->sp_speed > 0; table++)
9259816Smdodd		if (table->sp_speed <= speed) /* nearest one, rounded down */
9359816Smdodd			return (table->sp_code);
94131192Simp	return (1); /* 50, min and not hangup */
9559816Smdodd}
9659816Smdodd
9759816Smdoddint
9859816Smdoddttsetcompat(tp, com, data, term)
9959816Smdodd	register struct tty *tp;
10059816Smdodd	int *com;
10159816Smdodd	caddr_t data;
10259816Smdodd	struct termios *term;
10359816Smdodd{
10459816Smdodd	switch (*com) {
10559816Smdodd	case TIOCSETP:
10659816Smdodd	case TIOCSETN: {
10759816Smdodd		register struct sgttyb *sg = (struct sgttyb *)data;
10859816Smdodd		int speed;
10959816Smdodd
11059816Smdodd		if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0)
11159816Smdodd			return(EINVAL);
11259816Smdodd		else if (speed != ttcompatspeedtab(tp->t_ispeed, compatspeeds))
11359816Smdodd			term->c_ispeed = compatspcodes[speed];
11459816Smdodd		else
11559816Smdodd			term->c_ispeed = tp->t_ispeed;
11659816Smdodd		if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0)
11759816Smdodd			return(EINVAL);
11859816Smdodd		else if (speed != ttcompatspeedtab(tp->t_ospeed, compatspeeds))
11959816Smdodd			term->c_ospeed = compatspcodes[speed];
120131192Simp		else
12159816Smdodd			term->c_ospeed = tp->t_ospeed;
12259816Smdodd		term->c_cc[VERASE] = sg->sg_erase;
123131192Simp		term->c_cc[VKILL] = sg->sg_kill;
12459816Smdodd		tp->t_flags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
12559816Smdodd		ttcompatsetflags(tp, term);
12659816Smdodd		*com = (*com == TIOCSETP) ? TIOCSETAF : TIOCSETA;
12759816Smdodd		break;
128131192Simp	}
129131192Simp	case TIOCSETC: {
13059816Smdodd		struct tchars *tc = (struct tchars *)data;
13159816Smdodd		register cc_t *cc;
13259816Smdodd
13359816Smdodd		cc = term->c_cc;
13459816Smdodd		cc[VINTR] = tc->t_intrc;
135131192Simp		cc[VQUIT] = tc->t_quitc;
136179775Sjhb		cc[VSTART] = tc->t_startc;
137131192Simp		cc[VSTOP] = tc->t_stopc;
138179775Sjhb		cc[VEOF] = tc->t_eofc;
139131192Simp		cc[VEOL] = tc->t_brkc;
14059816Smdodd		if (tc->t_brkc == -1)
14159816Smdodd			cc[VEOL2] = _POSIX_VDISABLE;
142131192Simp		*com = TIOCSETA;
143179775Sjhb		break;
144179775Sjhb	}
14559816Smdodd	case TIOCSLTC: {
14659816Smdodd		struct ltchars *ltc = (struct ltchars *)data;
14759816Smdodd		register cc_t *cc;
14859816Smdodd
149131247Simp		cc = term->c_cc;
15059816Smdodd		cc[VSUSP] = ltc->t_suspc;
15159816Smdodd		cc[VDSUSP] = ltc->t_dsuspc;
152131192Simp		cc[VREPRINT] = ltc->t_rprntc;
15359816Smdodd		cc[VDISCARD] = ltc->t_flushc;
154131192Simp		cc[VWERASE] = ltc->t_werasc;
15559816Smdodd		cc[VLNEXT] = ltc->t_lnextc;
15659816Smdodd		*com = TIOCSETA;
157131247Simp		break;
158179775Sjhb	}
159179775Sjhb	case TIOCLBIS:
16059816Smdodd	case TIOCLBIC:
16159816Smdodd	case TIOCLSET:
16259816Smdodd		if (*com == TIOCLSET)
16359816Smdodd			tp->t_flags = (tp->t_flags&0xffff) | *(int *)data<<16;
16459816Smdodd		else {
16559816Smdodd			tp->t_flags =
166131192Simp			 (ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff);
16759816Smdodd			if (*com == TIOCLBIS)
16859816Smdodd				tp->t_flags |= *(int *)data<<16;
169131192Simp			else
170131192Simp				tp->t_flags &= ~(*(int *)data<<16);
17159816Smdodd		}
17259816Smdodd		ttcompatsetlflags(tp, term);
17359816Smdodd		*com = TIOCSETA;
17459816Smdodd		break;
17559816Smdodd	}
17659816Smdodd	return 0;
17759816Smdodd}
17859816Smdodd
17959816Smdodd/*ARGSUSED*/
18059816Smdoddint
181179775Sjhbttcompat(tp, com, data, flag)
18259816Smdodd	register struct tty *tp;
18359816Smdodd	int com;
18459816Smdodd	caddr_t data;
18559816Smdodd	int flag;
18659816Smdodd{
18759816Smdodd	switch (com) {
188131248Simp	case TIOCSETP:
189131248Simp	case TIOCSETN:
19059816Smdodd	case TIOCSETC:
19159816Smdodd	case TIOCSLTC:
19259816Smdodd	case TIOCLBIS:
19359816Smdodd	case TIOCLBIC:
19459816Smdodd	case TIOCLSET: {
19559816Smdodd		struct termios term;
19659816Smdodd		int error;
19759816Smdodd
198131192Simp		term = tp->t_termios;
19959816Smdodd		if ((error = ttsetcompat(tp, &com, data, &term)) != 0)
20059816Smdodd			return error;
20159816Smdodd		return ttioctl(tp, com, &term, flag);
20259816Smdodd	}
20359816Smdodd	case TIOCGETP: {
20459816Smdodd		register struct sgttyb *sg = (struct sgttyb *)data;
205131192Simp		register cc_t *cc = tp->t_cc;
20659816Smdodd
20759816Smdodd		sg->sg_ospeed = ttcompatspeedtab(tp->t_ospeed, compatspeeds);
20859816Smdodd		if (tp->t_ispeed == 0)
20959816Smdodd			sg->sg_ispeed = sg->sg_ospeed;
21059816Smdodd		else
211131192Simp			sg->sg_ispeed = ttcompatspeedtab(tp->t_ispeed, compatspeeds);
21259816Smdodd		sg->sg_erase = cc[VERASE];
21359816Smdodd		sg->sg_kill = cc[VKILL];
21459816Smdodd		sg->sg_flags = tp->t_flags = ttcompatgetflags(tp);
215131192Simp		break;
21659816Smdodd	}
21759816Smdodd	case TIOCGETC: {
218131192Simp		struct tchars *tc = (struct tchars *)data;
219131192Simp		register cc_t *cc = tp->t_cc;
220131192Simp
22159816Smdodd		tc->t_intrc = cc[VINTR];
222131192Simp		tc->t_quitc = cc[VQUIT];
223131192Simp		tc->t_startc = cc[VSTART];
224131247Simp		tc->t_stopc = cc[VSTOP];
225131192Simp		tc->t_eofc = cc[VEOF];
226131192Simp		tc->t_brkc = cc[VEOL];
22759816Smdodd		break;
22859816Smdodd	}
229131247Simp	case TIOCGLTC: {
23059816Smdodd		struct ltchars *ltc = (struct ltchars *)data;
23159816Smdodd		register cc_t *cc = tp->t_cc;
23259816Smdodd
23359816Smdodd		ltc->t_suspc = cc[VSUSP];
234131192Simp		ltc->t_dsuspc = cc[VDSUSP];
23559816Smdodd		ltc->t_rprntc = cc[VREPRINT];
23659816Smdodd		ltc->t_flushc = cc[VDISCARD];
237131192Simp		ltc->t_werasc = cc[VWERASE];
23859816Smdodd		ltc->t_lnextc = cc[VLNEXT];
23959816Smdodd		break;
24059816Smdodd	}
24159816Smdodd	case TIOCLGET:
24259816Smdodd		tp->t_flags =
24359816Smdodd		 (ttcompatgetflags(tp) & 0xffff0000UL)
24459816Smdodd		   | (tp->t_flags & 0xffff);
24559816Smdodd		*(int *)data = tp->t_flags>>16;
24659816Smdodd		if (ttydebug)
24759816Smdodd			printf("CLGET: returning %x\n", *(int *)data);
248131192Simp		break;
24959816Smdodd
25059816Smdodd	case OTIOCGETD:
25159816Smdodd		*(int *)data = tp->t_line ? tp->t_line : 2;
25259816Smdodd		break;
253182088Simp
254182088Simp	case OTIOCSETD: {
25559816Smdodd		int ldisczero = 0;
25659816Smdodd
25759816Smdodd		return (ttioctl(tp, TIOCSETD,
25859816Smdodd			*(int *)data == 2 ? (caddr_t)&ldisczero : data, flag));
25959816Smdodd	    }
26059816Smdodd
26159816Smdodd	case OTIOCCONS:
26259816Smdodd		*(int *)data = 1;
26359816Smdodd		return (ttioctl(tp, TIOCCONS, data, flag));
264131192Simp
26559816Smdodd	default:
26659816Smdodd		return (ENOIOCTL);
267131192Simp	}
268131192Simp	return (0);
269182088Simp}
27059816Smdodd
27159816Smdoddstatic int
27259816Smdoddttcompatgetflags(tp)
27359816Smdodd	register struct tty *tp;
27459816Smdodd{
27559816Smdodd	register tcflag_t iflag	= tp->t_iflag;
27659816Smdodd	register tcflag_t lflag	= tp->t_lflag;
277131192Simp	register tcflag_t oflag	= tp->t_oflag;
27859816Smdodd	register tcflag_t cflag	= tp->t_cflag;
27959816Smdodd	register flags = 0;
28059816Smdodd
28159816Smdodd	if (iflag&IXOFF)
282182088Simp		flags |= TANDEM;
28359816Smdodd	if (iflag&ICRNL || oflag&ONLCR)
28459816Smdodd		flags |= CRMOD;
28559816Smdodd	if ((cflag&CSIZE) == CS8) {
28659816Smdodd		flags |= PASS8;
28759816Smdodd		if (iflag&ISTRIP)
28859816Smdodd			flags |= ANYP;
28959816Smdodd	}
29059816Smdodd	else if (cflag&PARENB) {
29159816Smdodd		if (iflag&INPCK) {
29259816Smdodd			if (cflag&PARODD)
29359816Smdodd				flags |= ODDP;
29459816Smdodd			else
29559816Smdodd				flags |= EVENP;
29659816Smdodd		} else
29759816Smdodd			flags |= EVENP | ODDP;
298147256Sbrooks	}
29959816Smdodd
300131192Simp	if ((lflag&ICANON) == 0) {
30159816Smdodd		/* fudge */
30259816Smdodd		if (iflag&(INPCK|ISTRIP|IXON) || lflag&(IEXTEN|ISIG)
30359816Smdodd		    || cflag&(CSIZE|PARENB) != CS8)
30459816Smdodd			flags |= CBREAK;
305131192Simp		else
30659816Smdodd			flags |= RAW;
30759816Smdodd	}
30859816Smdodd	if (!(flags&RAW) && !(oflag&OPOST) && cflag&(CSIZE|PARENB) == CS8)
30959816Smdodd		flags |= LITOUT;
31059816Smdodd	if (cflag&MDMBUF)
31159816Smdodd		flags |= MDMBUF;
31259816Smdodd	if ((cflag&HUPCL) == 0)
31359816Smdodd		flags |= NOHANG;
31459816Smdodd	if (oflag&OXTABS)
31559816Smdodd		flags |= XTABS;
31659816Smdodd	if (lflag&ECHOE)
31759816Smdodd		flags |= CRTERA|CRTBS;
31859816Smdodd	if (lflag&ECHOKE)
31959816Smdodd		flags |= CRTKIL|CRTBS;
320131192Simp	if (lflag&ECHOPRT)
321131192Simp		flags |= PRTERA;
322131192Simp	if (lflag&ECHOCTL)
323131192Simp		flags |= CTLECH;
324131192Simp	if ((iflag&IXANY) == 0)
325131192Simp		flags |= DECCTQ;
326131192Simp	flags |= lflag&(ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH);
327131192Simp	if (ttydebug)
328131192Simp		printf("getflags: %x\n", flags);
329131192Simp	return (flags);
330131192Simp}
331131192Simp
332131192Simpstatic void
333131192Simpttcompatsetflags(tp, t)
334131192Simp	register struct tty *tp;
335131192Simp	register struct termios *t;
336131192Simp{
337131192Simp	register flags = tp->t_flags;
338	register tcflag_t iflag	= t->c_iflag;
339	register tcflag_t oflag	= t->c_oflag;
340	register tcflag_t lflag	= t->c_lflag;
341	register tcflag_t cflag	= t->c_cflag;
342
343	if (flags & RAW) {
344		iflag = IGNBRK;
345		lflag &= ~(ECHOCTL|ISIG|ICANON|IEXTEN);
346	} else {
347		iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR);
348		iflag |= BRKINT|IXON|IMAXBEL;
349		lflag |= ISIG|IEXTEN|ECHOCTL;	/* XXX was echoctl on ? */
350		if (flags & XTABS)
351			oflag |= OXTABS;
352		else
353			oflag &= ~OXTABS;
354		if (flags & CBREAK)
355			lflag &= ~ICANON;
356		else
357			lflag |= ICANON;
358		if (flags&CRMOD) {
359			iflag |= ICRNL;
360			oflag |= ONLCR;
361		} else {
362			iflag &= ~ICRNL;
363			oflag &= ~ONLCR;
364		}
365	}
366	if (flags&ECHO)
367		lflag |= ECHO;
368	else
369		lflag &= ~ECHO;
370
371	cflag &= ~(CSIZE|PARENB);
372	if (flags&(RAW|LITOUT|PASS8)) {
373		cflag |= CS8;
374		if (!(flags&(RAW|PASS8))
375		    || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
376			iflag |= ISTRIP;
377		else
378			iflag &= ~ISTRIP;
379		if (flags&(RAW|LITOUT))
380			oflag &= ~OPOST;
381		else
382			oflag |= OPOST;
383	} else {
384		cflag |= CS7|PARENB;
385		iflag |= ISTRIP;
386		oflag |= OPOST;
387	}
388	/* XXX don't set INPCK if RAW or PASS8? */
389	if ((flags&(EVENP|ODDP)) == EVENP) {
390		iflag |= INPCK;
391		cflag &= ~PARODD;
392	} else if ((flags&(EVENP|ODDP)) == ODDP) {
393		iflag |= INPCK;
394		cflag |= PARODD;
395	} else
396		iflag &= ~INPCK;
397	if (flags&TANDEM)
398		iflag |= IXOFF;
399	else
400		iflag &= ~IXOFF;
401	if ((flags&DECCTQ) == 0)
402		iflag |= IXANY;
403	else
404		iflag &= ~IXANY;
405	t->c_iflag = iflag;
406	t->c_oflag = oflag;
407	t->c_lflag = lflag;
408	t->c_cflag = cflag;
409}
410
411static void
412ttcompatsetlflags(tp, t)
413	register struct tty *tp;
414	register struct termios *t;
415{
416	register flags = tp->t_flags;
417	register tcflag_t iflag	= t->c_iflag;
418	register tcflag_t oflag	= t->c_oflag;
419	register tcflag_t lflag	= t->c_lflag;
420	register tcflag_t cflag	= t->c_cflag;
421
422	iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR);
423	if (flags&CRTERA)
424		lflag |= ECHOE;
425	else
426		lflag &= ~ECHOE;
427	if (flags&CRTKIL)
428		lflag |= ECHOKE;
429	else
430		lflag &= ~ECHOKE;
431	if (flags&PRTERA)
432		lflag |= ECHOPRT;
433	else
434		lflag &= ~ECHOPRT;
435	if (flags&CTLECH)
436		lflag |= ECHOCTL;
437	else
438		lflag &= ~ECHOCTL;
439	if (flags&TANDEM)
440		iflag |= IXOFF;
441	else
442		iflag &= ~IXOFF;
443	if ((flags&DECCTQ) == 0)
444		iflag |= IXANY;
445	else
446		iflag &= ~IXANY;
447	if (flags & MDMBUF)
448		cflag |= MDMBUF;
449	else
450		cflag &= ~MDMBUF;
451	if (flags&NOHANG)
452		cflag &= ~HUPCL;
453	else
454		cflag |= HUPCL;
455	lflag &= ~(TOSTOP|FLUSHO|PENDIN|NOFLSH);
456	lflag |= flags&(TOSTOP|FLUSHO|PENDIN|NOFLSH);
457
458	/*
459	 * The next if-else statement is copied from above so don't bother
460	 * checking it separately.  We could avoid fiddlling with the
461	 * character size if the mode is already RAW or if neither the
462	 * LITOUT bit or the PASS8 bit is being changed, but the delta of
463	 * the change is not available here and skipping the RAW case would
464	 * make the code different from above.
465	 */
466	cflag &= ~(CSIZE|PARENB);
467	if (flags&(RAW|LITOUT|PASS8)) {
468		cflag |= CS8;
469		if (!(flags&(RAW|PASS8))
470		    || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
471			iflag |= ISTRIP;
472		else
473			iflag &= ~ISTRIP;
474		if (flags&(RAW|LITOUT))
475			oflag &= ~OPOST;
476		else
477			oflag |= OPOST;
478	} else {
479		cflag |= CS7|PARENB;
480		iflag |= ISTRIP;
481		oflag |= OPOST;
482	}
483	t->c_iflag = iflag;
484	t->c_oflag = oflag;
485	t->c_lflag = lflag;
486	t->c_cflag = cflag;
487}
488#endif	/* COMPAT_43 || COMPAT_SUNOS */
489