tty_compat.c revision 127911
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 127911 2004-04-05 21:03:37Z imp $");
34
35#include "opt_compat.h"
36
37/*
38 * mapping routines for old line discipline (yuck)
39 */
40#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
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(speed, table)
86	int speed;
87	register 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
97int
98ttsetcompat(tp, com, data, term)
99	register struct tty *tp;
100	u_long *com;
101	caddr_t data;
102	struct termios *term;
103{
104	switch (*com) {
105	case TIOCSETP:
106	case TIOCSETN: {
107		register struct sgttyb *sg = (struct sgttyb *)data;
108		int speed;
109
110		if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0)
111			return(EINVAL);
112		else if (speed != ttcompatspeedtab(tp->t_ispeed, compatspeeds))
113			term->c_ispeed = compatspcodes[speed];
114		else
115			term->c_ispeed = tp->t_ispeed;
116		if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0)
117			return(EINVAL);
118		else if (speed != ttcompatspeedtab(tp->t_ospeed, compatspeeds))
119			term->c_ospeed = compatspcodes[speed];
120		else
121			term->c_ospeed = tp->t_ospeed;
122		term->c_cc[VERASE] = sg->sg_erase;
123		term->c_cc[VKILL] = sg->sg_kill;
124		tp->t_flags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
125		ttcompatsetflags(tp, term);
126		*com = (*com == TIOCSETP) ? TIOCSETAF : TIOCSETA;
127		break;
128	}
129	case TIOCSETC: {
130		struct tchars *tc = (struct tchars *)data;
131		register cc_t *cc;
132
133		cc = term->c_cc;
134		cc[VINTR] = tc->t_intrc;
135		cc[VQUIT] = tc->t_quitc;
136		cc[VSTART] = tc->t_startc;
137		cc[VSTOP] = tc->t_stopc;
138		cc[VEOF] = tc->t_eofc;
139		cc[VEOL] = tc->t_brkc;
140		if (tc->t_brkc == -1)
141			cc[VEOL2] = _POSIX_VDISABLE;
142		*com = TIOCSETA;
143		break;
144	}
145	case TIOCSLTC: {
146		struct ltchars *ltc = (struct ltchars *)data;
147		register cc_t *cc;
148
149		cc = term->c_cc;
150		cc[VSUSP] = ltc->t_suspc;
151		cc[VDSUSP] = ltc->t_dsuspc;
152		cc[VREPRINT] = ltc->t_rprntc;
153		cc[VDISCARD] = ltc->t_flushc;
154		cc[VWERASE] = ltc->t_werasc;
155		cc[VLNEXT] = ltc->t_lnextc;
156		*com = TIOCSETA;
157		break;
158	}
159	case TIOCLBIS:
160	case TIOCLBIC:
161	case TIOCLSET:
162		if (*com == TIOCLSET)
163			tp->t_flags = (tp->t_flags&0xffff) | *(int *)data<<16;
164		else {
165			tp->t_flags =
166			 (ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff);
167			if (*com == TIOCLBIS)
168				tp->t_flags |= *(int *)data<<16;
169			else
170				tp->t_flags &= ~(*(int *)data<<16);
171		}
172		ttcompatsetlflags(tp, term);
173		*com = TIOCSETA;
174		break;
175	}
176	return 0;
177}
178
179/*ARGSUSED*/
180int
181ttcompat(tp, com, data, flag)
182	register struct tty *tp;
183	u_long com;
184	caddr_t data;
185	int flag;
186{
187	switch (com) {
188	case TIOCSETP:
189	case TIOCSETN:
190	case TIOCSETC:
191	case TIOCSLTC:
192	case TIOCLBIS:
193	case TIOCLBIC:
194	case TIOCLSET: {
195		struct termios term;
196		int error;
197
198		term = tp->t_termios;
199		if ((error = ttsetcompat(tp, &com, data, &term)) != 0)
200			return error;
201		return ttioctl(tp, com, &term, flag);
202	}
203	case TIOCGETP: {
204		register struct sgttyb *sg = (struct sgttyb *)data;
205		register cc_t *cc = tp->t_cc;
206
207		sg->sg_ospeed = ttcompatspeedtab(tp->t_ospeed, compatspeeds);
208		if (tp->t_ispeed == 0)
209			sg->sg_ispeed = sg->sg_ospeed;
210		else
211			sg->sg_ispeed = ttcompatspeedtab(tp->t_ispeed, compatspeeds);
212		sg->sg_erase = cc[VERASE];
213		sg->sg_kill = cc[VKILL];
214		sg->sg_flags = tp->t_flags = ttcompatgetflags(tp);
215		break;
216	}
217	case TIOCGETC: {
218		struct tchars *tc = (struct tchars *)data;
219		register cc_t *cc = tp->t_cc;
220
221		tc->t_intrc = cc[VINTR];
222		tc->t_quitc = cc[VQUIT];
223		tc->t_startc = cc[VSTART];
224		tc->t_stopc = cc[VSTOP];
225		tc->t_eofc = cc[VEOF];
226		tc->t_brkc = cc[VEOL];
227		break;
228	}
229	case TIOCGLTC: {
230		struct ltchars *ltc = (struct ltchars *)data;
231		register cc_t *cc = tp->t_cc;
232
233		ltc->t_suspc = cc[VSUSP];
234		ltc->t_dsuspc = cc[VDSUSP];
235		ltc->t_rprntc = cc[VREPRINT];
236		ltc->t_flushc = cc[VDISCARD];
237		ltc->t_werasc = cc[VWERASE];
238		ltc->t_lnextc = cc[VLNEXT];
239		break;
240	}
241	case TIOCLGET:
242		tp->t_flags =
243		 (ttcompatgetflags(tp) & 0xffff0000UL)
244		   | (tp->t_flags & 0xffff);
245		*(int *)data = tp->t_flags>>16;
246		if (ttydebug)
247			printf("CLGET: returning %x\n", *(int *)data);
248		break;
249
250	case OTIOCGETD:
251		*(int *)data = tp->t_line ? tp->t_line : 2;
252		break;
253
254	case OTIOCSETD: {
255		int ldisczero = 0;
256
257		return (ttioctl(tp, TIOCSETD,
258			*(int *)data == 2 ? (caddr_t)&ldisczero : data, flag));
259	    }
260
261	case OTIOCCONS:
262		*(int *)data = 1;
263		return (ttioctl(tp, TIOCCONS, data, flag));
264
265	default:
266		return (ENOIOCTL);
267	}
268	return (0);
269}
270
271static int
272ttcompatgetflags(tp)
273	register struct tty *tp;
274{
275	register tcflag_t iflag	= tp->t_iflag;
276	register tcflag_t lflag	= tp->t_lflag;
277	register tcflag_t oflag	= tp->t_oflag;
278	register tcflag_t cflag	= tp->t_cflag;
279	register int flags = 0;
280
281	if (iflag&IXOFF)
282		flags |= TANDEM;
283	if (iflag&ICRNL || oflag&ONLCR)
284		flags |= CRMOD;
285	if ((cflag&CSIZE) == CS8) {
286		flags |= PASS8;
287		if (iflag&ISTRIP)
288			flags |= ANYP;
289	}
290	else if (cflag&PARENB) {
291		if (iflag&INPCK) {
292			if (cflag&PARODD)
293				flags |= ODDP;
294			else
295				flags |= EVENP;
296		} else
297			flags |= EVENP | ODDP;
298	}
299
300	if ((lflag&ICANON) == 0) {
301		/* fudge */
302		if (iflag&(INPCK|ISTRIP|IXON) || lflag&(IEXTEN|ISIG)
303		    || (cflag&(CSIZE|PARENB)) != CS8)
304			flags |= CBREAK;
305		else
306			flags |= RAW;
307	}
308	if (!(flags&RAW) && !(oflag&OPOST) && (cflag&(CSIZE|PARENB)) == CS8)
309		flags |= LITOUT;
310	if (cflag&MDMBUF)
311		flags |= MDMBUF;
312	if ((cflag&HUPCL) == 0)
313		flags |= NOHANG;
314	if (oflag&OXTABS)
315		flags |= XTABS;
316	if (lflag&ECHOE)
317		flags |= CRTERA|CRTBS;
318	if (lflag&ECHOKE)
319		flags |= CRTKIL|CRTBS;
320	if (lflag&ECHOPRT)
321		flags |= PRTERA;
322	if (lflag&ECHOCTL)
323		flags |= CTLECH;
324	if ((iflag&IXANY) == 0)
325		flags |= DECCTQ;
326	flags |= lflag&(ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH);
327	if (ttydebug)
328		printf("getflags: %x\n", flags);
329	return (flags);
330}
331
332static void
333ttcompatsetflags(tp, t)
334	register struct tty *tp;
335	register struct termios *t;
336{
337	register int 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 int 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