xref: /netbsd-src/sys/compat/common/tty_43.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
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