xref: /netbsd-src/sys/compat/common/tty_43.c (revision 8ac07aec990b9d2e483062509d0a9fa5b4f57cf2)
1 /*	$NetBSD: tty_43.c,v 1.26 2008/04/24 15:35:27 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5  * 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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the NetBSD
18  *	Foundation, Inc. and its contributors.
19  * 4. Neither the name of The NetBSD Foundation nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /*-
37  * Copyright (c) 1982, 1986, 1991, 1993
38  *	The Regents of the University of California.  All rights reserved.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  *	@(#)tty_compat.c	8.2 (Berkeley) 1/9/95
65  */
66 
67 /*
68  * mapping routines for old line discipline (yuck)
69  */
70 
71 #include <sys/cdefs.h>
72 __KERNEL_RCSID(0, "$NetBSD: tty_43.c,v 1.26 2008/04/24 15:35:27 ad Exp $");
73 
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/ioctl.h>
77 #include <sys/proc.h>
78 #include <sys/conf.h>
79 #include <sys/tty.h>
80 #include <sys/termios.h>
81 #include <sys/file.h>
82 #include <sys/kernel.h>
83 #include <sys/syslog.h>
84 #include <sys/ioctl_compat.h>
85 
86 /*
87  * XXX libcompat files should be included with config attributes
88  */
89 #ifdef COMPAT_OLDTTY
90 
91 int ttydebug = 0;
92 
93 static const struct speedtab compatspeeds[] = {
94 #define MAX_SPEED	17
95 	{ 115200, 17 },
96 	{ 57600, 16 },
97 	{ 38400, 15 },
98 	{ 19200, 14 },
99 	{ 9600,	13 },
100 	{ 4800,	12 },
101 	{ 2400,	11 },
102 	{ 1800,	10 },
103 	{ 1200,	9 },
104 	{ 600,	8 },
105 	{ 300,	7 },
106 	{ 200,	6 },
107 	{ 150,	5 },
108 	{ 134,	4 },
109 	{ 110,	3 },
110 	{ 75,	2 },
111 	{ 50,	1 },
112 	{ 0,	0 },
113 	{ -1,	-1 },
114 };
115 static const int compatspcodes[] = {
116 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
117 	1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200
118 };
119 
120 static int ttcompatgetflags(struct tty *);
121 static void ttcompatsetflags(struct tty *, struct termios *);
122 static void ttcompatsetlflags(struct tty *, struct termios *);
123 
124 /*ARGSUSED*/
125 int
126 ttcompat(struct tty *tp, u_long com, void *data, int flag, struct lwp *l)
127 {
128 
129 	switch (com) {
130 	case TIOCGETP: {
131 		struct sgttyb *sg = (struct sgttyb *)data;
132 		u_char *cc;
133 		int speed;
134 
135 		mutex_spin_enter(&tty_lock);
136 		cc = tp->t_cc;
137 		speed = ttspeedtab(tp->t_ospeed, compatspeeds);
138 		sg->sg_ospeed = (speed == -1) ? MAX_SPEED : speed;
139 		if (tp->t_ispeed == 0)
140 			sg->sg_ispeed = sg->sg_ospeed;
141 		else {
142 			speed = ttspeedtab(tp->t_ispeed, compatspeeds);
143 			sg->sg_ispeed = (speed == -1) ? MAX_SPEED : speed;
144 		}
145 		sg->sg_erase = cc[VERASE];
146 		sg->sg_kill = cc[VKILL];
147 		sg->sg_flags = ttcompatgetflags(tp);
148 		mutex_spin_exit(&tty_lock);
149 		break;
150 	}
151 
152 	case TIOCSETP:
153 	case TIOCSETN: {
154 		struct sgttyb *sg = (struct sgttyb *)data;
155 		struct termios term;
156 		int speed;
157 
158 		mutex_spin_enter(&tty_lock);
159 		term = tp->t_termios;
160 		if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0)
161 			term.c_ispeed = speed;
162 		else
163 			term.c_ispeed = compatspcodes[speed];
164 		if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0)
165 			term.c_ospeed = speed;
166 		else
167 			term.c_ospeed = compatspcodes[speed];
168 		term.c_cc[VERASE] = sg->sg_erase;
169 		term.c_cc[VKILL] = sg->sg_kill;
170 		tp->t_flags = (ttcompatgetflags(tp)&0xffff0000) | (sg->sg_flags&0xffff);
171 		ttcompatsetflags(tp, &term);
172 		mutex_spin_exit(&tty_lock);
173 		return (ttioctl(tp, com == TIOCSETP ? TIOCSETAF : TIOCSETA,
174 			(void *)&term, flag, l));
175 	}
176 
177 	case TIOCGETC: {
178 		struct tchars *tc = (struct tchars *)data;
179 		u_char *cc = tp->t_cc;
180 
181 		tc->t_intrc = cc[VINTR];
182 		tc->t_quitc = cc[VQUIT];
183 		tc->t_startc = cc[VSTART];
184 		tc->t_stopc = cc[VSTOP];
185 		tc->t_eofc = cc[VEOF];
186 		tc->t_brkc = cc[VEOL];
187 		break;
188 	}
189 	case TIOCSETC: {
190 		struct tchars *tc = (struct tchars *)data;
191 		u_char *cc = tp->t_cc;
192 
193 		cc[VINTR] = tc->t_intrc;
194 		cc[VQUIT] = tc->t_quitc;
195 		cc[VSTART] = tc->t_startc;
196 		cc[VSTOP] = tc->t_stopc;
197 		cc[VEOF] = tc->t_eofc;
198 		cc[VEOL] = tc->t_brkc;
199 		if (tc->t_brkc == (char)-1)
200 			cc[VEOL2] = _POSIX_VDISABLE;
201 		break;
202 	}
203 	case TIOCSLTC: {
204 		struct ltchars *ltc = (struct ltchars *)data;
205 		u_char *cc = tp->t_cc;
206 
207 		cc[VSUSP] = ltc->t_suspc;
208 		cc[VDSUSP] = ltc->t_dsuspc;
209 		cc[VREPRINT] = ltc->t_rprntc;
210 		cc[VDISCARD] = ltc->t_flushc;
211 		cc[VWERASE] = ltc->t_werasc;
212 		cc[VLNEXT] = ltc->t_lnextc;
213 		break;
214 	}
215 	case TIOCGLTC: {
216 		struct ltchars *ltc = (struct ltchars *)data;
217 		u_char *cc = tp->t_cc;
218 
219 		ltc->t_suspc = cc[VSUSP];
220 		ltc->t_dsuspc = cc[VDSUSP];
221 		ltc->t_rprntc = cc[VREPRINT];
222 		ltc->t_flushc = cc[VDISCARD];
223 		ltc->t_werasc = cc[VWERASE];
224 		ltc->t_lnextc = cc[VLNEXT];
225 		break;
226 	}
227 	case TIOCLBIS:
228 	case TIOCLBIC:
229 	case TIOCLSET: {
230 		struct termios term;
231 		int flags;
232 
233 		mutex_spin_enter(&tty_lock);
234 		term = tp->t_termios;
235 		flags = ttcompatgetflags(tp);
236 		switch (com) {
237 		case TIOCLSET:
238 			tp->t_flags = (flags&0xffff) | (*(int *)data<<16);
239 			break;
240 		case TIOCLBIS:
241 			tp->t_flags = flags | (*(int *)data<<16);
242 			break;
243 		case TIOCLBIC:
244 			tp->t_flags = flags & ~(*(int *)data<<16);
245 			break;
246 		}
247 		ttcompatsetlflags(tp, &term);
248 		mutex_spin_exit(&tty_lock);
249 		return (ttioctl(tp, TIOCSETA, (void *)&term, flag, l));
250 	}
251 	case TIOCLGET:
252 		mutex_spin_enter(&tty_lock);
253 		*(int *)data = ttcompatgetflags(tp)>>16;
254 		mutex_spin_exit(&tty_lock);
255 		if (ttydebug)
256 			printf("CLGET: returning %x\n", *(int *)data);
257 		break;
258 
259 	case OTIOCGETD:
260 		mutex_spin_enter(&tty_lock);
261 		*(int *)data = (tp->t_linesw == NULL) ?
262 		    2 /* XXX old NTTYDISC */ : tp->t_linesw->l_no;
263 		mutex_spin_exit(&tty_lock);
264 		break;
265 
266 	case OTIOCSETD: {
267 		int ldisczero = 0;
268 
269 		return (ttioctl(tp, TIOCSETD,
270 			*(int *)data == 2 ? (void *)&ldisczero : data, flag,
271 			l));
272 	    }
273 
274 	case OTIOCCONS:
275 		*(int *)data = 1;
276 		return (ttioctl(tp, TIOCCONS, data, flag, l));
277 
278 	case TIOCHPCL:
279 		mutex_spin_enter(&tty_lock);
280 		SET(tp->t_cflag, HUPCL);
281 		mutex_spin_exit(&tty_lock);
282 		break;
283 
284 	case TIOCGSID:
285 		mutex_enter(proc_lock);
286 		if (tp->t_session == NULL) {
287 			mutex_exit(proc_lock);
288 			return ENOTTY;
289 		}
290 		if (tp->t_session->s_leader == NULL) {
291 			mutex_exit(proc_lock);
292 			return ENOTTY;
293 		}
294 		*(int *) data =  tp->t_session->s_leader->p_pid;
295 		mutex_exit(proc_lock);
296 		break;
297 
298 	default:
299 		return (EPASSTHROUGH);
300 	}
301 	return (0);
302 }
303 
304 static int
305 ttcompatgetflags(struct tty *tp)
306 {
307 	tcflag_t iflag = tp->t_iflag;
308 	tcflag_t lflag = tp->t_lflag;
309 	tcflag_t oflag = tp->t_oflag;
310 	tcflag_t cflag = tp->t_cflag;
311 	int flags = 0;
312 
313 	KASSERT(mutex_owned(&tty_lock));
314 
315 	if (ISSET(iflag, IXOFF))
316 		SET(flags, TANDEM);
317 	if (ISSET(iflag, ICRNL) || ISSET(oflag, ONLCR))
318 		SET(flags, CRMOD);
319 	if (ISSET(cflag, PARENB)) {
320 		if (ISSET(iflag, INPCK)) {
321 			if (ISSET(cflag, PARODD))
322 				SET(flags, ODDP);
323 			else
324 				SET(flags, EVENP);
325 		} else
326 			SET(flags, ANYP);
327 	}
328 
329 	if (!ISSET(lflag, ICANON)) {
330 		/* fudge */
331 		if (ISSET(iflag, IXON) || ISSET(lflag, ISIG|IEXTEN) ||
332 		    ISSET(cflag, PARENB))
333 			SET(flags, CBREAK);
334 		else
335 			SET(flags, RAW);
336 	}
337 
338 	if (ISSET(flags, RAW))
339 		SET(flags, ISSET(tp->t_flags, LITOUT|PASS8));
340 	else if (ISSET(cflag, CSIZE) == CS8) {
341 		if (!ISSET(oflag, OPOST))
342 			SET(flags, LITOUT);
343 		if (!ISSET(iflag, ISTRIP))
344 			SET(flags, PASS8);
345 	}
346 
347 	if (ISSET(cflag, MDMBUF))
348 		SET(flags, MDMBUF);
349 	if (!ISSET(cflag, HUPCL))
350 		SET(flags, NOHANG);
351 	if (ISSET(oflag, OXTABS))
352 		SET(flags, XTABS);
353 	if (ISSET(lflag, ECHOE))
354 		SET(flags, CRTERA|CRTBS);
355 	if (ISSET(lflag, ECHOKE))
356 		SET(flags, CRTKIL|CRTBS);
357 	if (ISSET(lflag, ECHOPRT))
358 		SET(flags, PRTERA);
359 	if (ISSET(lflag, ECHOCTL))
360 		SET(flags, CTLECH);
361 	if (!ISSET(iflag, IXANY))
362 		SET(flags, DECCTQ);
363 	SET(flags, ISSET(lflag, ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH));
364 	if (ttydebug)
365 		printf("getflags: %x\n", flags);
366 	return (flags);
367 }
368 
369 static void
370 ttcompatsetflags(struct tty *tp, struct termios *t)
371 {
372 	int flags = tp->t_flags;
373 
374 	KASSERT(mutex_owned(&tty_lock));
375 
376 	tcflag_t iflag = t->c_iflag;
377 	tcflag_t oflag = t->c_oflag;
378 	tcflag_t lflag = t->c_lflag;
379 	tcflag_t cflag = t->c_cflag;
380 
381 	if (ISSET(flags, TANDEM))
382 		SET(iflag, IXOFF);
383 	else
384 		CLR(iflag, IXOFF);
385 	if (ISSET(flags, ECHO))
386 		SET(lflag, ECHO);
387 	else
388 		CLR(lflag, ECHO);
389 	if (ISSET(flags, CRMOD)) {
390 		SET(iflag, ICRNL);
391 		SET(oflag, ONLCR);
392 	} else {
393 		CLR(iflag, ICRNL);
394 		CLR(oflag, ONLCR);
395 	}
396 	if (ISSET(flags, XTABS))
397 		SET(oflag, OXTABS);
398 	else
399 		CLR(oflag, OXTABS);
400 
401 
402 	if (ISSET(flags, RAW)) {
403 		iflag &= IXOFF;
404 		CLR(lflag, ISIG|ICANON|IEXTEN);
405 		CLR(cflag, PARENB);
406 	} else {
407 		SET(iflag, BRKINT|IXON|IMAXBEL);
408 		SET(lflag, ISIG|IEXTEN);
409 		if (ISSET(flags, CBREAK))
410 			CLR(lflag, ICANON);
411 		else
412 			SET(lflag, ICANON);
413 		switch (ISSET(flags, ANYP)) {
414 		case 0:
415 			CLR(cflag, PARENB);
416 			break;
417 		case ANYP:
418 			SET(cflag, PARENB);
419 			CLR(iflag, INPCK);
420 			break;
421 		case EVENP:
422 			SET(cflag, PARENB);
423 			SET(iflag, INPCK);
424 			CLR(cflag, PARODD);
425 			break;
426 		case ODDP:
427 			SET(cflag, PARENB);
428 			SET(iflag, INPCK);
429 			SET(cflag, PARODD);
430 			break;
431 		}
432 	}
433 
434 	if (ISSET(flags, RAW|LITOUT|PASS8)) {
435 		CLR(cflag, CSIZE);
436 		SET(cflag, CS8);
437 		if (!ISSET(flags, RAW|PASS8))
438 			SET(iflag, ISTRIP);
439 		else
440 			CLR(iflag, ISTRIP);
441 		if (!ISSET(flags, RAW|LITOUT))
442 			SET(oflag, OPOST);
443 		else
444 			CLR(oflag, OPOST);
445 	} else {
446 		CLR(cflag, CSIZE);
447 		SET(cflag, CS7);
448 		SET(iflag, ISTRIP);
449 		SET(oflag, OPOST);
450 	}
451 
452 	t->c_iflag = iflag;
453 	t->c_oflag = oflag;
454 	t->c_lflag = lflag;
455 	t->c_cflag = cflag;
456 }
457 
458 static void
459 ttcompatsetlflags(struct tty *tp, struct termios *t)
460 {
461 	int flags = tp->t_flags;
462 	tcflag_t iflag = t->c_iflag;
463 	tcflag_t oflag = t->c_oflag;
464 	tcflag_t lflag = t->c_lflag;
465 	tcflag_t cflag = t->c_cflag;
466 
467 	KASSERT(mutex_owned(&tty_lock));
468 
469 	/* Nothing we can do with CRTBS. */
470 	if (ISSET(flags, PRTERA))
471 		SET(lflag, ECHOPRT);
472 	else
473 		CLR(lflag, ECHOPRT);
474 	if (ISSET(flags, CRTERA))
475 		SET(lflag, ECHOE);
476 	else
477 		CLR(lflag, ECHOE);
478 	/* Nothing we can do with TILDE. */
479 	if (ISSET(flags, MDMBUF))
480 		SET(cflag, MDMBUF);
481 	else
482 		CLR(cflag, MDMBUF);
483 	if (ISSET(flags, NOHANG))
484 		CLR(cflag, HUPCL);
485 	else
486 		SET(cflag, HUPCL);
487 	if (ISSET(flags, CRTKIL))
488 		SET(lflag, ECHOKE);
489 	else
490 		CLR(lflag, ECHOKE);
491 	if (ISSET(flags, CTLECH))
492 		SET(lflag, ECHOCTL);
493 	else
494 		CLR(lflag, ECHOCTL);
495 	if (!ISSET(flags, DECCTQ))
496 		SET(iflag, IXANY);
497 	else
498 		CLR(iflag, IXANY);
499 	CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH);
500 	SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH));
501 
502 	if (ISSET(flags, RAW|LITOUT|PASS8)) {
503 		CLR(cflag, CSIZE);
504 		SET(cflag, CS8);
505 		if (!ISSET(flags, RAW|PASS8))
506 			SET(iflag, ISTRIP);
507 		else
508 			CLR(iflag, ISTRIP);
509 		if (!ISSET(flags, RAW|LITOUT))
510 			SET(oflag, OPOST);
511 		else
512 			CLR(oflag, OPOST);
513 	} else {
514 		CLR(cflag, CSIZE);
515 		SET(cflag, CS7);
516 		SET(iflag, ISTRIP);
517 		SET(oflag, OPOST);
518 	}
519 
520 	t->c_iflag = iflag;
521 	t->c_oflag = oflag;
522 	t->c_lflag = lflag;
523 	t->c_cflag = cflag;
524 }
525 
526 #endif /* COMPAT_OLDTTY */
527