fd5cbdb949f8110ea3bf338c61818350773df1b7
[dragonfly.git] / sys / kern / tty_compat.c
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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *      @(#)tty_compat.c        8.1 (Berkeley) 6/10/93
34  * $FreeBSD: src/sys/kern/tty_compat.c,v 1.29 1999/08/28 00:46:20 peter Exp $
35  */
36
37 /*
38  * mapping routines for old line discipline (yuck)
39  */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/ioctl_compat.h>
44 #include <sys/tty.h>
45 #include <sys/kernel.h>
46 #include <sys/sysctl.h>
47
48 static int ttcompatgetflags     (struct tty     *tp);
49 static void ttcompatsetflags    (struct tty     *tp, struct termios *t);
50 static void ttcompatsetlflags   (struct tty     *tp, struct termios *t);
51 static int ttcompatspeedtab     (int speed, struct speedtab *table);
52
53 static int ttydebug = 0;
54 SYSCTL_INT(_debug, OID_AUTO, ttydebug, CTLFLAG_RW, &ttydebug, 0,
55     "tty debugging");
56
57 static 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 };
79 static int compatspcodes[] = {
80         0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
81         1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200,
82 };
83
84 static int
85 ttcompatspeedtab(int speed, struct speedtab *table)
86 {
87         if (speed == 0)
88                 return (0); /* hangup */
89         for ( ; table->sp_speed > 0; table++)
90                 if (table->sp_speed <= speed) /* nearest one, rounded down */
91                         return (table->sp_code);
92         return (1); /* 50, min and not hangup */
93 }
94
95 int
96 ttsetcompat(struct tty *tp, u_long *com, caddr_t data, struct termios *term)
97 {
98         switch (*com) {
99         case TIOCSETP:
100         case TIOCSETN: {
101                 struct sgttyb *sg = (struct sgttyb *)data;
102                 int speed;
103
104                 if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0)
105                         return(EINVAL);
106                 else if (speed != ttcompatspeedtab(tp->t_ispeed, compatspeeds))
107                         term->c_ispeed = compatspcodes[speed];
108                 else
109                         term->c_ispeed = tp->t_ispeed;
110                 if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0)
111                         return(EINVAL);
112                 else if (speed != ttcompatspeedtab(tp->t_ospeed, compatspeeds))
113                         term->c_ospeed = compatspcodes[speed];
114                 else
115                         term->c_ospeed = tp->t_ospeed;
116                 term->c_cc[VERASE] = sg->sg_erase;
117                 term->c_cc[VKILL] = sg->sg_kill;
118                 tp->t_flags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff);
119                 ttcompatsetflags(tp, term);
120                 *com = (*com == TIOCSETP) ? TIOCSETAF : TIOCSETA;
121                 break;
122         }
123         case TIOCSETC: {
124                 struct tchars *tc = (struct tchars *)data;
125                 cc_t *cc;
126
127                 cc = term->c_cc;
128                 cc[VINTR] = tc->t_intrc;
129                 cc[VQUIT] = tc->t_quitc;
130                 cc[VSTART] = tc->t_startc;
131                 cc[VSTOP] = tc->t_stopc;
132                 cc[VEOF] = tc->t_eofc;
133                 cc[VEOL] = tc->t_brkc;
134                 if (tc->t_brkc == -1)
135                         cc[VEOL2] = _POSIX_VDISABLE;
136                 *com = TIOCSETA;
137                 break;
138         }
139         case TIOCSLTC: {
140                 struct ltchars *ltc = (struct ltchars *)data;
141                 cc_t *cc;
142
143                 cc = term->c_cc;
144                 cc[VSUSP] = ltc->t_suspc;
145                 cc[VDSUSP] = ltc->t_dsuspc;
146                 cc[VREPRINT] = ltc->t_rprntc;
147                 cc[VDISCARD] = ltc->t_flushc;
148                 cc[VWERASE] = ltc->t_werasc;
149                 cc[VLNEXT] = ltc->t_lnextc;
150                 *com = TIOCSETA;
151                 break;
152         }
153         case TIOCLBIS:
154         case TIOCLBIC:
155         case TIOCLSET:
156                 if (*com == TIOCLSET)
157                         tp->t_flags = (tp->t_flags&0xffff) | *(int *)data<<16;
158                 else {
159                         tp->t_flags =
160                          (ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff);
161                         if (*com == TIOCLBIS)
162                                 tp->t_flags |= *(int *)data<<16;
163                         else
164                                 tp->t_flags &= ~(*(int *)data<<16);
165                 }
166                 ttcompatsetlflags(tp, term);
167                 *com = TIOCSETA;
168                 break;
169         }
170         return 0;
171 }
172
173 /*ARGSUSED*/
174 int
175 ttcompat(struct tty *tp, u_long com, caddr_t data, int flag)
176 {
177         switch (com) {
178         case TIOCSETP:
179         case TIOCSETN:
180         case TIOCSETC:
181         case TIOCSLTC:
182         case TIOCLBIS:
183         case TIOCLBIC:
184         case TIOCLSET: {
185                 struct termios term;
186                 int error;
187
188                 term = tp->t_termios;
189                 if ((error = ttsetcompat(tp, &com, data, &term)) != 0)
190                         return error;
191                 return ttioctl(tp, com, &term, flag);
192         }
193         case TIOCGETP: {
194                 struct sgttyb *sg = (struct sgttyb *)data;
195                 cc_t *cc = tp->t_cc;
196
197                 sg->sg_ospeed = ttcompatspeedtab(tp->t_ospeed, compatspeeds);
198                 if (tp->t_ispeed == 0)
199                         sg->sg_ispeed = sg->sg_ospeed;
200                 else
201                         sg->sg_ispeed = ttcompatspeedtab(tp->t_ispeed, compatspeeds);
202                 sg->sg_erase = cc[VERASE];
203                 sg->sg_kill = cc[VKILL];
204                 sg->sg_flags = tp->t_flags = ttcompatgetflags(tp);
205                 break;
206         }
207         case TIOCGETC: {
208                 struct tchars *tc = (struct tchars *)data;
209                 cc_t *cc = tp->t_cc;
210
211                 tc->t_intrc = cc[VINTR];
212                 tc->t_quitc = cc[VQUIT];
213                 tc->t_startc = cc[VSTART];
214                 tc->t_stopc = cc[VSTOP];
215                 tc->t_eofc = cc[VEOF];
216                 tc->t_brkc = cc[VEOL];
217                 break;
218         }
219         case TIOCGLTC: {
220                 struct ltchars *ltc = (struct ltchars *)data;
221                 cc_t *cc = tp->t_cc;
222
223                 ltc->t_suspc = cc[VSUSP];
224                 ltc->t_dsuspc = cc[VDSUSP];
225                 ltc->t_rprntc = cc[VREPRINT];
226                 ltc->t_flushc = cc[VDISCARD];
227                 ltc->t_werasc = cc[VWERASE];
228                 ltc->t_lnextc = cc[VLNEXT];
229                 break;
230         }
231         case TIOCLGET:
232                 tp->t_flags =
233                  (ttcompatgetflags(tp) & 0xffff0000UL)
234                    | (tp->t_flags & 0xffff);
235                 *(int *)data = tp->t_flags>>16;
236                 if (ttydebug)
237                         kprintf("CLGET: returning %x\n", *(int *)data);
238                 break;
239
240         case OTIOCGETD:
241                 *(int *)data = tp->t_line ? tp->t_line : 2;
242                 break;
243
244         case OTIOCSETD: {
245                 int ldisczero = 0;
246
247                 return (ttioctl(tp, TIOCSETD,
248                         *(int *)data == 2 ? (caddr_t)&ldisczero : data, flag));
249             }
250
251         case OTIOCCONS:
252                 *(int *)data = 1;
253                 return (ttioctl(tp, TIOCCONS, data, flag));
254
255         default:
256                 return (ENOIOCTL);
257         }
258         return (0);
259 }
260
261 static int
262 ttcompatgetflags(struct tty *tp)
263 {
264         tcflag_t iflag  = tp->t_iflag;
265         tcflag_t lflag  = tp->t_lflag;
266         tcflag_t oflag  = tp->t_oflag;
267         tcflag_t cflag  = tp->t_cflag;
268         int flags = 0;
269
270         if (iflag&IXOFF)
271                 flags |= TANDEM;
272         if (iflag&ICRNL || oflag&ONLCR)
273                 flags |= CRMOD;
274         if ((cflag&CSIZE) == CS8) {
275                 flags |= PASS8;
276                 if (iflag&ISTRIP)
277                         flags |= ANYP;
278         }
279         else if (cflag&PARENB) {
280                 if (iflag&INPCK) {
281                         if (cflag&PARODD)
282                                 flags |= ODDP;
283                         else
284                                 flags |= EVENP;
285                 } else
286                         flags |= EVENP | ODDP;
287         }
288
289         if ((lflag&ICANON) == 0) {
290                 /* fudge */
291                 if (iflag&(INPCK|ISTRIP|IXON) || lflag&(IEXTEN|ISIG)
292                     || (cflag&(CSIZE|PARENB)) != CS8)
293                         flags |= CBREAK;
294                 else
295                         flags |= RAW;
296         }
297         if (!(flags&RAW) && !(oflag&OPOST) && (cflag&(CSIZE|PARENB)) == CS8)
298                 flags |= LITOUT;
299         if (cflag&MDMBUF)
300                 flags |= MDMBUF;
301         if ((cflag&HUPCL) == 0)
302                 flags |= NOHANG;
303         if (oflag&OXTABS)
304                 flags |= XTABS;
305         if (lflag&ECHOE)
306                 flags |= CRTERA|CRTBS;
307         if (lflag&ECHOKE)
308                 flags |= CRTKIL|CRTBS;
309         if (lflag&ECHOPRT)
310                 flags |= PRTERA;
311         if (lflag&ECHOCTL)
312                 flags |= CTLECH;
313         if ((iflag&IXANY) == 0)
314                 flags |= DECCTQ;
315         flags |= lflag&(ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH);
316         if (ttydebug)
317                 kprintf("getflags: %x\n", flags);
318         return (flags);
319 }
320
321 static void
322 ttcompatsetflags(struct tty *tp, struct termios *t)
323 {
324         int flags = tp->t_flags;
325         tcflag_t iflag  = t->c_iflag;
326         tcflag_t oflag  = t->c_oflag;
327         tcflag_t lflag  = t->c_lflag;
328         tcflag_t cflag  = t->c_cflag;
329
330         if (flags & RAW) {
331                 iflag = IGNBRK;
332                 lflag &= ~(ECHOCTL|ISIG|ICANON|IEXTEN);
333         } else {
334                 iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR);
335                 iflag |= BRKINT|IXON|IMAXBEL;
336                 lflag |= ISIG|IEXTEN|ECHOCTL;   /* XXX was echoctl on ? */
337                 if (flags & XTABS)
338                         oflag |= OXTABS;
339                 else
340                         oflag &= ~OXTABS;
341                 if (flags & CBREAK)
342                         lflag &= ~ICANON;
343                 else
344                         lflag |= ICANON;
345                 if (flags&CRMOD) {
346                         iflag |= ICRNL;
347                         oflag |= ONLCR;
348                 } else {
349                         iflag &= ~ICRNL;
350                         oflag &= ~ONLCR;
351                 }
352         }
353         if (flags&ECHO)
354                 lflag |= ECHO;
355         else
356                 lflag &= ~ECHO;
357
358         cflag &= ~(CSIZE|PARENB);
359         if (flags&(RAW|LITOUT|PASS8)) {
360                 cflag |= CS8;
361                 if (!(flags&(RAW|PASS8))
362                     || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
363                         iflag |= ISTRIP;
364                 else
365                         iflag &= ~ISTRIP;
366                 if (flags&(RAW|LITOUT))
367                         oflag &= ~OPOST;
368                 else
369                         oflag |= OPOST;
370         } else {
371                 cflag |= CS7|PARENB;
372                 iflag |= ISTRIP;
373                 oflag |= OPOST;
374         }
375         /* XXX don't set INPCK if RAW or PASS8? */
376         if ((flags&(EVENP|ODDP)) == EVENP) {
377                 iflag |= INPCK;
378                 cflag &= ~PARODD;
379         } else if ((flags&(EVENP|ODDP)) == ODDP) {
380                 iflag |= INPCK;
381                 cflag |= PARODD;
382         } else
383                 iflag &= ~INPCK;
384         if (flags&TANDEM)
385                 iflag |= IXOFF;
386         else
387                 iflag &= ~IXOFF;
388         if ((flags&DECCTQ) == 0)
389                 iflag |= IXANY;
390         else
391                 iflag &= ~IXANY;
392         t->c_iflag = iflag;
393         t->c_oflag = oflag;
394         t->c_lflag = lflag;
395         t->c_cflag = cflag;
396 }
397
398 static void
399 ttcompatsetlflags(struct tty *tp, struct termios *t)
400 {
401         int flags = tp->t_flags;
402         tcflag_t iflag  = t->c_iflag;
403         tcflag_t oflag  = t->c_oflag;
404         tcflag_t lflag  = t->c_lflag;
405         tcflag_t cflag  = t->c_cflag;
406
407         iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR);
408         if (flags&CRTERA)
409                 lflag |= ECHOE;
410         else
411                 lflag &= ~ECHOE;
412         if (flags&CRTKIL)
413                 lflag |= ECHOKE;
414         else
415                 lflag &= ~ECHOKE;
416         if (flags&PRTERA)
417                 lflag |= ECHOPRT;
418         else
419                 lflag &= ~ECHOPRT;
420         if (flags&CTLECH)
421                 lflag |= ECHOCTL;
422         else
423                 lflag &= ~ECHOCTL;
424         if (flags&TANDEM)
425                 iflag |= IXOFF;
426         else
427                 iflag &= ~IXOFF;
428         if ((flags&DECCTQ) == 0)
429                 iflag |= IXANY;
430         else
431                 iflag &= ~IXANY;
432         if (flags & MDMBUF)
433                 cflag |= MDMBUF;
434         else
435                 cflag &= ~MDMBUF;
436         if (flags&NOHANG)
437                 cflag &= ~HUPCL;
438         else
439                 cflag |= HUPCL;
440         lflag &= ~(TOSTOP|FLUSHO|PENDIN|NOFLSH);
441         lflag |= flags&(TOSTOP|FLUSHO|PENDIN|NOFLSH);
442
443         /*
444          * The next if-else statement is copied from above so don't bother
445          * checking it separately.  We could avoid fiddlling with the
446          * character size if the mode is already RAW or if neither the
447          * LITOUT bit or the PASS8 bit is being changed, but the delta of
448          * the change is not available here and skipping the RAW case would
449          * make the code different from above.
450          */
451         cflag &= ~(CSIZE|PARENB);
452         if (flags&(RAW|LITOUT|PASS8)) {
453                 cflag |= CS8;
454                 if (!(flags&(RAW|PASS8))
455                     || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
456                         iflag |= ISTRIP;
457                 else
458                         iflag &= ~ISTRIP;
459                 if (flags&(RAW|LITOUT))
460                         oflag &= ~OPOST;
461                 else
462                         oflag |= OPOST;
463         } else {
464                 cflag |= CS7|PARENB;
465                 iflag |= ISTRIP;
466                 oflag |= OPOST;
467         }
468         t->c_iflag = iflag;
469         t->c_oflag = oflag;
470         t->c_lflag = lflag;
471         t->c_cflag = cflag;
472 }