]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/tty_compat.c
xnu-344.23.tar.gz
[apple/xnu.git] / bsd / kern / tty_compat.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1997 Apple Computer, Inc. All Rights Reserved */
23 /*-
24 * Copyright (c) 1982, 1986, 1991, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * @(#)tty_compat.c 8.1 (Berkeley) 6/10/93
56 */
57
58 /*
59 * mapping routines for old line discipline (yuck)
60 */
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/ioctl.h>
65 #include <sys/proc.h>
66 #include <sys/tty.h>
67 #include <sys/termios.h>
68 #include <sys/file.h>
69 #include <sys/conf.h>
70 #include <sys/kernel.h>
71 #include <sys/sysctl.h>
72 #include <sys/syslog.h>
73
74 /* NeXT Move define down here cause COMPAT_43 not valid earlier */
75 #if COMPAT_43 || defined(COMPAT_SUNOS)
76
77 static int ttcompatgetflags __P((struct tty *tp));
78 static void ttcompatsetflags __P((struct tty *tp, struct termios *t));
79 static void ttcompatsetlflags __P((struct tty *tp, struct termios *t));
80 static int ttcompatspeedtab __P((int speed, struct speedtab *table));
81
82
83 static int ttydebug = 0;
84
85 #ifndef NeXT
86 SYSCTL_INT(_debug, OID_AUTO, ttydebug, CTLFLAG_RW, &ttydebug, 0, "");
87 #endif
88
89 static struct speedtab compatspeeds[] = {
90 #define MAX_SPEED 17
91 { 115200, 17 },
92 { 57600, 16 },
93 { 38400, 15 },
94 { 19200, 14 },
95 { 9600, 13 },
96 { 4800, 12 },
97 { 2400, 11 },
98 { 1800, 10 },
99 { 1200, 9 },
100 { 600, 8 },
101 { 300, 7 },
102 { 200, 6 },
103 { 150, 5 },
104 { 134, 4 },
105 { 110, 3 },
106 { 75, 2 },
107 { 50, 1 },
108 { 0, 0 },
109 { -1, -1 },
110 };
111 static int compatspcodes[] = {
112 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
113 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200,
114 };
115
116 static int
117 ttcompatspeedtab(speed, table)
118 int speed;
119 register struct speedtab *table;
120 {
121 if (speed == 0)
122 return (0); /* hangup */
123 for ( ; table->sp_speed > 0; table++)
124 if (table->sp_speed <= speed) /* nearest one, rounded down */
125 return (table->sp_code);
126 return (1); /* 50, min and not hangup */
127 }
128
129 #ifndef NeXT
130 int
131 ttsetcompat(tp, com, data, term)
132 register struct tty *tp;
133 int *com;
134 caddr_t data;
135 struct termios *term;
136 #else
137 __private_extern__ int
138 ttsetcompat(tp, com, data, term)
139 register struct tty *tp;
140 u_long *com;
141 caddr_t data;
142 struct termios *term;
143 #endif /* !NeXT */
144 {
145 switch (*com) {
146 case TIOCSETP:
147 case TIOCSETN: {
148 register struct sgttyb *sg = (struct sgttyb *)data;
149 int speed;
150
151 if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0)
152 return(EINVAL);
153 else if (speed != ttcompatspeedtab(tp->t_ispeed, compatspeeds))
154 term->c_ispeed = compatspcodes[speed];
155 else
156 term->c_ispeed = tp->t_ispeed;
157 if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0)
158 return(EINVAL);
159 else if (speed != ttcompatspeedtab(tp->t_ospeed, compatspeeds))
160 term->c_ospeed = compatspcodes[speed];
161 else
162 term->c_ospeed = tp->t_ospeed;
163 term->c_cc[VERASE] = sg->sg_erase;
164 term->c_cc[VKILL] = sg->sg_kill;
165 tp->t_flags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
166 ttcompatsetflags(tp, term);
167 *com = (*com == TIOCSETP) ? TIOCSETAF : TIOCSETA;
168 break;
169 }
170 case TIOCSETC: {
171 struct tchars *tc = (struct tchars *)data;
172 register cc_t *cc;
173
174 cc = term->c_cc;
175 cc[VINTR] = tc->t_intrc;
176 cc[VQUIT] = tc->t_quitc;
177 cc[VSTART] = tc->t_startc;
178 cc[VSTOP] = tc->t_stopc;
179 cc[VEOF] = tc->t_eofc;
180 cc[VEOL] = tc->t_brkc;
181 if (tc->t_brkc == -1)
182 cc[VEOL2] = _POSIX_VDISABLE;
183 *com = TIOCSETA;
184 break;
185 }
186 case TIOCSLTC: {
187 struct ltchars *ltc = (struct ltchars *)data;
188 register cc_t *cc;
189
190 cc = term->c_cc;
191 cc[VSUSP] = ltc->t_suspc;
192 cc[VDSUSP] = ltc->t_dsuspc;
193 cc[VREPRINT] = ltc->t_rprntc;
194 cc[VDISCARD] = ltc->t_flushc;
195 cc[VWERASE] = ltc->t_werasc;
196 cc[VLNEXT] = ltc->t_lnextc;
197 *com = TIOCSETA;
198 break;
199 }
200 case TIOCLBIS:
201 case TIOCLBIC:
202 case TIOCLSET:
203 if (*com == TIOCLSET)
204 tp->t_flags = (tp->t_flags&0xffff) | *(int *)data<<16;
205 else {
206 tp->t_flags =
207 (ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff);
208 if (*com == TIOCLBIS)
209 tp->t_flags |= *(int *)data<<16;
210 else
211 tp->t_flags &= ~(*(int *)data<<16);
212 }
213 ttcompatsetlflags(tp, term);
214 *com = TIOCSETA;
215 break;
216 }
217 return 0;
218 }
219
220 /*ARGSUSED*/
221 #ifndef NeXT
222 int
223 ttcompat(tp, com, data, flag)
224 register struct tty *tp;
225 int com;
226 caddr_t data;
227 int flag;
228 #else
229 __private_extern__ int
230 ttcompat(tp, com, data, flag, p)
231 register struct tty *tp;
232 u_long com;
233 caddr_t data;
234 int flag;
235 struct proc *p;
236 #endif /* !NeXT */
237 {
238 switch (com) {
239 case TIOCSETP:
240 case TIOCSETN:
241 case TIOCSETC:
242 case TIOCSLTC:
243 case TIOCLBIS:
244 case TIOCLBIC:
245 case TIOCLSET: {
246 struct termios term;
247 int error;
248
249 term = tp->t_termios;
250 if ((error = ttsetcompat(tp, &com, data, &term)) != 0)
251 return error;
252 #ifdef NeXT
253 return ttioctl(tp, com, (caddr_t) &term, flag, p);
254 #else
255 return ttioctl(tp, com, &term, flag);
256 #endif
257 }
258 case TIOCGETP: {
259 register struct sgttyb *sg = (struct sgttyb *)data;
260 register cc_t *cc = tp->t_cc;
261
262 sg->sg_ospeed = ttcompatspeedtab(tp->t_ospeed, compatspeeds);
263 if (tp->t_ispeed == 0)
264 sg->sg_ispeed = sg->sg_ospeed;
265 else
266 sg->sg_ispeed = ttcompatspeedtab(tp->t_ispeed, compatspeeds);
267 sg->sg_erase = cc[VERASE];
268 sg->sg_kill = cc[VKILL];
269 sg->sg_flags = tp->t_flags = ttcompatgetflags(tp);
270 break;
271 }
272 case TIOCGETC: {
273 struct tchars *tc = (struct tchars *)data;
274 register cc_t *cc = tp->t_cc;
275
276 tc->t_intrc = cc[VINTR];
277 tc->t_quitc = cc[VQUIT];
278 tc->t_startc = cc[VSTART];
279 tc->t_stopc = cc[VSTOP];
280 tc->t_eofc = cc[VEOF];
281 tc->t_brkc = cc[VEOL];
282 break;
283 }
284 case TIOCGLTC: {
285 struct ltchars *ltc = (struct ltchars *)data;
286 register cc_t *cc = tp->t_cc;
287
288 ltc->t_suspc = cc[VSUSP];
289 ltc->t_dsuspc = cc[VDSUSP];
290 ltc->t_rprntc = cc[VREPRINT];
291 ltc->t_flushc = cc[VDISCARD];
292 ltc->t_werasc = cc[VWERASE];
293 ltc->t_lnextc = cc[VLNEXT];
294 break;
295 }
296 case TIOCLGET:
297 tp->t_flags =
298 (ttcompatgetflags(tp) & 0xffff0000UL)
299 | (tp->t_flags & 0xffff);
300 *(int *)data = tp->t_flags>>16;
301 #ifndef NeXT
302 if (ttydebug)
303 printf("CLGET: returning %x\n", *(int *)data);
304 #endif
305 break;
306
307 case OTIOCGETD:
308 *(int *)data = tp->t_line ? tp->t_line : 2;
309 break;
310
311 #ifndef NeXT
312 case OTIOCSETD: {
313 int ldisczero = 0;
314
315 return (ttioctl(tp, TIOCSETD,
316 *(int *)data == 2 ? (caddr_t)&ldisczero : data, flag));
317 }
318
319 case OTIOCCONS:
320 *(int *)data = 1;
321 return (ttioctl(tp, TIOCCONS, data, flag));
322 #else
323 case OTIOCSETD: {
324 int ldisczero = 0;
325
326 return (ttioctl(tp, TIOCSETD,
327 *(int *)data == 2 ? (caddr_t)&ldisczero : data, flag, p));
328 }
329
330 case OTIOCCONS:
331 *(int *)data = 1;
332 return (ttioctl(tp, TIOCCONS, data, flag, p));
333
334 case TIOCGSID:
335 if (tp->t_session == NULL)
336 return ENOTTY;
337
338 if (tp->t_session->s_leader == NULL)
339 return ENOTTY;
340
341 *(int *) data = tp->t_session->s_leader->p_pid;
342 break;
343 #endif /* NeXT */
344
345 default:
346 return (-1);
347 }
348 return (0);
349 }
350
351 static int
352 ttcompatgetflags(tp)
353 register struct tty *tp;
354 {
355 register tcflag_t iflag = tp->t_iflag;
356 register tcflag_t lflag = tp->t_lflag;
357 register tcflag_t oflag = tp->t_oflag;
358 register tcflag_t cflag = tp->t_cflag;
359 register flags = 0;
360
361 if (iflag&IXOFF)
362 flags |= TANDEM;
363 if (iflag&ICRNL || oflag&ONLCR)
364 flags |= CRMOD;
365 if ((cflag&CSIZE) == CS8) {
366 flags |= PASS8;
367 if (iflag&ISTRIP)
368 flags |= ANYP;
369 }
370 else if (cflag&PARENB) {
371 if (iflag&INPCK) {
372 if (cflag&PARODD)
373 flags |= ODDP;
374 else
375 flags |= EVENP;
376 } else
377 flags |= EVENP | ODDP;
378 }
379
380 if ((lflag&ICANON) == 0) {
381 /* fudge */
382 if (iflag&(INPCK|ISTRIP|IXON) || lflag&(IEXTEN|ISIG)
383 || cflag&(CSIZE|PARENB) != CS8)
384 flags |= CBREAK;
385 else
386 flags |= RAW;
387 }
388 if (!(flags&RAW) && !(oflag&OPOST) && cflag&(CSIZE|PARENB) == CS8)
389 flags |= LITOUT;
390 if (cflag&MDMBUF)
391 flags |= MDMBUF;
392 if ((cflag&HUPCL) == 0)
393 flags |= NOHANG;
394 if (oflag&OXTABS)
395 flags |= XTABS;
396 if (lflag&ECHOE)
397 flags |= CRTERA|CRTBS;
398 if (lflag&ECHOKE)
399 flags |= CRTKIL|CRTBS;
400 if (lflag&ECHOPRT)
401 flags |= PRTERA;
402 if (lflag&ECHOCTL)
403 flags |= CTLECH;
404 if ((iflag&IXANY) == 0)
405 flags |= DECCTQ;
406 flags |= lflag&(ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH);
407 #ifndef NeXT
408 if (ttydebug)
409 printf("getflags: %x\n", flags);
410 #endif
411 return (flags);
412 }
413
414 static void
415 ttcompatsetflags(tp, t)
416 register struct tty *tp;
417 register struct termios *t;
418 {
419 register flags = tp->t_flags;
420 register tcflag_t iflag = t->c_iflag;
421 register tcflag_t oflag = t->c_oflag;
422 register tcflag_t lflag = t->c_lflag;
423 register tcflag_t cflag = t->c_cflag;
424
425 if (flags & RAW) {
426 iflag = IGNBRK;
427 lflag &= ~(ECHOCTL|ISIG|ICANON|IEXTEN);
428 } else {
429 iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR);
430 iflag |= BRKINT|IXON|IMAXBEL;
431 lflag |= ISIG|IEXTEN|ECHOCTL; /* XXX was echoctl on ? */
432 if (flags & XTABS)
433 oflag |= OXTABS;
434 else
435 oflag &= ~OXTABS;
436 if (flags & CBREAK)
437 lflag &= ~ICANON;
438 else
439 lflag |= ICANON;
440 if (flags&CRMOD) {
441 iflag |= ICRNL;
442 oflag |= ONLCR;
443 } else {
444 iflag &= ~ICRNL;
445 oflag &= ~ONLCR;
446 }
447 }
448 if (flags&ECHO)
449 lflag |= ECHO;
450 else
451 lflag &= ~ECHO;
452
453 cflag &= ~(CSIZE|PARENB);
454 if (flags&(RAW|LITOUT|PASS8)) {
455 cflag |= CS8;
456 if (!(flags&(RAW|PASS8))
457 || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
458 iflag |= ISTRIP;
459 else
460 iflag &= ~ISTRIP;
461 if (flags&(RAW|LITOUT))
462 oflag &= ~OPOST;
463 else
464 oflag |= OPOST;
465 } else {
466 cflag |= CS7|PARENB;
467 iflag |= ISTRIP;
468 oflag |= OPOST;
469 }
470 /* XXX don't set INPCK if RAW or PASS8? */
471 if ((flags&(EVENP|ODDP)) == EVENP) {
472 iflag |= INPCK;
473 cflag &= ~PARODD;
474 } else if ((flags&(EVENP|ODDP)) == ODDP) {
475 iflag |= INPCK;
476 cflag |= PARODD;
477 } else
478 iflag &= ~INPCK;
479 if (flags&TANDEM)
480 iflag |= IXOFF;
481 else
482 iflag &= ~IXOFF;
483 if ((flags&DECCTQ) == 0)
484 iflag |= IXANY;
485 else
486 iflag &= ~IXANY;
487 t->c_iflag = iflag;
488 t->c_oflag = oflag;
489 t->c_lflag = lflag;
490 t->c_cflag = cflag;
491 }
492
493 static void
494 ttcompatsetlflags(tp, t)
495 register struct tty *tp;
496 register struct termios *t;
497 {
498 register flags = tp->t_flags;
499 register tcflag_t iflag = t->c_iflag;
500 register tcflag_t oflag = t->c_oflag;
501 register tcflag_t lflag = t->c_lflag;
502 register tcflag_t cflag = t->c_cflag;
503
504 iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR);
505 if (flags&CRTERA)
506 lflag |= ECHOE;
507 else
508 lflag &= ~ECHOE;
509 if (flags&CRTKIL)
510 lflag |= ECHOKE;
511 else
512 lflag &= ~ECHOKE;
513 if (flags&PRTERA)
514 lflag |= ECHOPRT;
515 else
516 lflag &= ~ECHOPRT;
517 if (flags&CTLECH)
518 lflag |= ECHOCTL;
519 else
520 lflag &= ~ECHOCTL;
521 if (flags&TANDEM)
522 iflag |= IXOFF;
523 else
524 iflag &= ~IXOFF;
525 if ((flags&DECCTQ) == 0)
526 iflag |= IXANY;
527 else
528 iflag &= ~IXANY;
529 if (flags & MDMBUF)
530 cflag |= MDMBUF;
531 else
532 cflag &= ~MDMBUF;
533 if (flags&NOHANG)
534 cflag &= ~HUPCL;
535 else
536 cflag |= HUPCL;
537 lflag &= ~(TOSTOP|FLUSHO|PENDIN|NOFLSH);
538 lflag |= flags&(TOSTOP|FLUSHO|PENDIN|NOFLSH);
539
540 /*
541 * The next if-else statement is copied from above so don't bother
542 * checking it separately. We could avoid fiddlling with the
543 * character size if the mode is already RAW or if neither the
544 * LITOUT bit or the PASS8 bit is being changed, but the delta of
545 * the change is not available here and skipping the RAW case would
546 * make the code different from above.
547 */
548 cflag &= ~(CSIZE|PARENB);
549 if (flags&(RAW|LITOUT|PASS8)) {
550 cflag |= CS8;
551 if (!(flags&(RAW|PASS8))
552 || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
553 iflag |= ISTRIP;
554 else
555 iflag &= ~ISTRIP;
556 if (flags&(RAW|LITOUT))
557 oflag &= ~OPOST;
558 else
559 oflag |= OPOST;
560 } else {
561 cflag |= CS7|PARENB;
562 iflag |= ISTRIP;
563 oflag |= OPOST;
564 }
565 t->c_iflag = iflag;
566 t->c_oflag = oflag;
567 t->c_lflag = lflag;
568 t->c_cflag = cflag;
569 }
570 #endif /* COMPAT_43 || COMPAT_SUNOS */