FreeBSD kernel kern code
tty_compat.c
Go to the documentation of this file.
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("$BSDSUniX$");
34 
35 #include "opt_compat.h"
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 struct speedtab {
49  int sp_speed; /* Speed. */
50  int sp_code; /* Code. */
51 };
52 
53 static int ttcompatgetflags(struct tty *tp);
54 static void ttcompatsetflags(struct tty *tp, struct termios *t);
55 static void ttcompatsetlflags(struct tty *tp, struct termios *t);
56 static int ttcompatspeedtab(int speed, struct speedtab *table);
57 
58 static int ttydebug = 0;
59 SYSCTL_INT(_debug, OID_AUTO, ttydebug, CTLFLAG_RW, &ttydebug, 0, "");
60 
61 static struct speedtab compatspeeds[] = {
62 #define MAX_SPEED 17
63  { 115200, 17 },
64  { 57600, 16 },
65  { 38400, 15 },
66  { 19200, 14 },
67  { 9600, 13 },
68  { 4800, 12 },
69  { 2400, 11 },
70  { 1800, 10 },
71  { 1200, 9 },
72  { 600, 8 },
73  { 300, 7 },
74  { 200, 6 },
75  { 150, 5 },
76  { 134, 4 },
77  { 110, 3 },
78  { 75, 2 },
79  { 50, 1 },
80  { 0, 0 },
81  { -1, -1 },
82 };
83 static int compatspcodes[] = {
84  0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
85  1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200,
86 };
87 
88 static int
89 ttcompatspeedtab(int speed, struct speedtab *table)
90 {
91  if (speed == 0)
92  return (0); /* hangup */
93  for ( ; table->sp_speed > 0; table++)
94  if (table->sp_speed <= speed) /* nearest one, rounded down */
95  return (table->sp_code);
96  return (1); /* 50, min and not hangup */
97 }
98 
99 static int
100 ttsetcompat(struct tty *tp, u_long *com, caddr_t data, struct termios *term)
101 {
102  switch (*com) {
103  case TIOCSETP:
104  case TIOCSETN: {
105  struct sgttyb *sg = (struct sgttyb *)data;
106  int speed;
107 
108  if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0)
109  return(EINVAL);
110  else if (speed != ttcompatspeedtab(tp->t_termios.c_ispeed,
111  compatspeeds))
112  term->c_ispeed = compatspcodes[speed];
113  else
114  term->c_ispeed = tp->t_termios.c_ispeed;
115  if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0)
116  return(EINVAL);
117  else if (speed != ttcompatspeedtab(tp->t_termios.c_ospeed,
118  compatspeeds))
119  term->c_ospeed = compatspcodes[speed];
120  else
121  term->c_ospeed = tp->t_termios.c_ospeed;
122  term->c_cc[VERASE] = sg->sg_erase;
123  term->c_cc[VKILL] = sg->sg_kill;
124  tp->t_compatflags = (tp->t_compatflags&0xffff0000) |
125  (sg->sg_flags&0xffff);
126  ttcompatsetflags(tp, term);
127  *com = (*com == TIOCSETP) ? TIOCSETAF : TIOCSETA;
128  break;
129  }
130  case TIOCSETC: {
131  struct tchars *tc = (struct tchars *)data;
132  cc_t *cc;
133 
134  cc = term->c_cc;
135  cc[VINTR] = tc->t_intrc;
136  cc[VQUIT] = tc->t_quitc;
137  cc[VSTART] = tc->t_startc;
138  cc[VSTOP] = tc->t_stopc;
139  cc[VEOF] = tc->t_eofc;
140  cc[VEOL] = tc->t_brkc;
141  if (tc->t_brkc == (char)_POSIX_VDISABLE)
142  cc[VEOL2] = _POSIX_VDISABLE;
143  *com = TIOCSETA;
144  break;
145  }
146  case TIOCSLTC: {
147  struct ltchars *ltc = (struct ltchars *)data;
148  cc_t *cc;
149 
150  cc = term->c_cc;
151  cc[VSUSP] = ltc->t_suspc;
152  cc[VDSUSP] = ltc->t_dsuspc;
153  cc[VREPRINT] = ltc->t_rprntc;
154  cc[VDISCARD] = ltc->t_flushc;
155  cc[VWERASE] = ltc->t_werasc;
156  cc[VLNEXT] = ltc->t_lnextc;
157  *com = TIOCSETA;
158  break;
159  }
160  case TIOCLBIS:
161  case TIOCLBIC:
162  case TIOCLSET:
163  if (*com == TIOCLSET)
164  tp->t_compatflags = (tp->t_compatflags&0xffff) |
165  *(int *)data<<16;
166  else {
167  tp->t_compatflags = (ttcompatgetflags(tp)&0xffff0000) |
168  (tp->t_compatflags&0xffff);
169  if (*com == TIOCLBIS)
170  tp->t_compatflags |= *(int *)data<<16;
171  else
172  tp->t_compatflags &= ~(*(int *)data<<16);
173  }
174  ttcompatsetlflags(tp, term);
175  *com = TIOCSETA;
176  break;
177  }
178  return 0;
179 }
180 
181 /*ARGSUSED*/
182 int
183 tty_ioctl_compat(struct tty *tp, u_long com, caddr_t data, int fflag,
184  struct thread *td)
185 {
186  switch (com) {
187  case TIOCSETP:
188  case TIOCSETN:
189  case TIOCSETC:
190  case TIOCSLTC:
191  case TIOCLBIS:
192  case TIOCLBIC:
193  case TIOCLSET: {
194  struct termios term;
195  int error;
196 
197  term = tp->t_termios;
198  if ((error = ttsetcompat(tp, &com, data, &term)) != 0)
199  return error;
200  return tty_ioctl(tp, com, &term, fflag, td);
201  }
202  case TIOCGETP: {
203  struct sgttyb *sg = (struct sgttyb *)data;
204  cc_t *cc = tp->t_termios.c_cc;
205 
206  sg->sg_ospeed = ttcompatspeedtab(tp->t_termios.c_ospeed,
207  compatspeeds);
208  if (tp->t_termios.c_ispeed == 0)
209  sg->sg_ispeed = sg->sg_ospeed;
210  else
211  sg->sg_ispeed = ttcompatspeedtab(tp->t_termios.c_ispeed,
212  compatspeeds);
213  sg->sg_erase = cc[VERASE];
214  sg->sg_kill = cc[VKILL];
215  sg->sg_flags = tp->t_compatflags = ttcompatgetflags(tp);
216  break;
217  }
218  case TIOCGETC: {
219  struct tchars *tc = (struct tchars *)data;
220  cc_t *cc = tp->t_termios.c_cc;
221 
222  tc->t_intrc = cc[VINTR];
223  tc->t_quitc = cc[VQUIT];
224  tc->t_startc = cc[VSTART];
225  tc->t_stopc = cc[VSTOP];
226  tc->t_eofc = cc[VEOF];
227  tc->t_brkc = cc[VEOL];
228  break;
229  }
230  case TIOCGLTC: {
231  struct ltchars *ltc = (struct ltchars *)data;
232  cc_t *cc = tp->t_termios.c_cc;
233 
234  ltc->t_suspc = cc[VSUSP];
235  ltc->t_dsuspc = cc[VDSUSP];
236  ltc->t_rprntc = cc[VREPRINT];
237  ltc->t_flushc = cc[VDISCARD];
238  ltc->t_werasc = cc[VWERASE];
239  ltc->t_lnextc = cc[VLNEXT];
240  break;
241  }
242  case TIOCLGET:
243  tp->t_compatflags =
244  (ttcompatgetflags(tp) & 0xffff0000UL)
245  | (tp->t_compatflags & 0xffff);
246  *(int *)data = tp->t_compatflags>>16;
247  if (ttydebug)
248  printf("CLGET: returning %x\n", *(int *)data);
249  break;
250 
251  case OTIOCGETD:
252  *(int *)data = 2;
253  break;
254 
255  case OTIOCSETD: {
256  int ldisczero = 0;
257 
258  return (tty_ioctl(tp, TIOCSETD,
259  *(int *)data == 2 ? (caddr_t)&ldisczero : data,
260  fflag, td));
261  }
262 
263  case OTIOCCONS:
264  *(int *)data = 1;
265  return (tty_ioctl(tp, TIOCCONS, data, fflag, td));
266 
267  default:
268  return (ENOIOCTL);
269  }
270  return (0);
271 }
272 
273 static int
274 ttcompatgetflags(struct tty *tp)
275 {
276  tcflag_t iflag = tp->t_termios.c_iflag;
277  tcflag_t lflag = tp->t_termios.c_lflag;
278  tcflag_t oflag = tp->t_termios.c_oflag;
279  tcflag_t cflag = tp->t_termios.c_cflag;
280  int flags = 0;
281 
282  if (iflag&IXOFF)
283  flags |= TANDEM;
284  if (iflag&ICRNL || oflag&ONLCR)
285  flags |= CRMOD;
286  if ((cflag&CSIZE) == CS8) {
287  flags |= PASS8;
288  if (iflag&ISTRIP)
289  flags |= ANYP;
290  }
291  else if (cflag&PARENB) {
292  if (iflag&INPCK) {
293  if (cflag&PARODD)
294  flags |= ODDP;
295  else
296  flags |= EVENP;
297  } else
298  flags |= EVENP | ODDP;
299  }
300 
301  if ((lflag&ICANON) == 0) {
302  /* fudge */
303  if (iflag&(INPCK|ISTRIP|IXON) || lflag&(IEXTEN|ISIG)
304  || (cflag&(CSIZE|PARENB)) != CS8)
305  flags |= CBREAK;
306  else
307  flags |= RAW;
308  }
309  if (!(flags&RAW) && !(oflag&OPOST) && (cflag&(CSIZE|PARENB)) == CS8)
310  flags |= LITOUT;
311  if (cflag&MDMBUF)
312  flags |= MDMBUF;
313  if ((cflag&HUPCL) == 0)
314  flags |= NOHANG;
315  if (oflag&TAB3)
316  flags |= XTABS;
317  if (lflag&ECHOE)
318  flags |= CRTERA|CRTBS;
319  if (lflag&ECHOKE)
320  flags |= CRTKIL|CRTBS;
321  if (lflag&ECHOPRT)
322  flags |= PRTERA;
323  if (lflag&ECHOCTL)
324  flags |= CTLECH;
325  if ((iflag&IXANY) == 0)
326  flags |= DECCTQ;
327  flags |= lflag&(ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH);
328  if (ttydebug)
329  printf("getflags: %x\n", flags);
330  return (flags);
331 }
332 
333 static void
334 ttcompatsetflags(struct tty *tp, struct termios *t)
335 {
336  int flags = tp->t_compatflags;
337  tcflag_t iflag = t->c_iflag;
338  tcflag_t oflag = t->c_oflag;
339  tcflag_t lflag = t->c_lflag;
340  tcflag_t cflag = t->c_cflag;
341 
342  if (flags & RAW) {
343  iflag = IGNBRK;
344  lflag &= ~(ECHOCTL|ISIG|ICANON|IEXTEN);
345  } else {
346  iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR);
347  iflag |= BRKINT|IXON|IMAXBEL;
348  lflag |= ISIG|IEXTEN|ECHOCTL; /* XXX was echoctl on ? */
349  if (flags & XTABS)
350  oflag |= TAB3;
351  else
352  oflag &= ~TAB3;
353  if (flags & CBREAK)
354  lflag &= ~ICANON;
355  else
356  lflag |= ICANON;
357  if (flags&CRMOD) {
358  iflag |= ICRNL;
359  oflag |= ONLCR;
360  } else {
361  iflag &= ~ICRNL;
362  oflag &= ~ONLCR;
363  }
364  }
365  if (flags&ECHO)
366  lflag |= ECHO;
367  else
368  lflag &= ~ECHO;
369 
370  cflag &= ~(CSIZE|PARENB);
371  if (flags&(RAW|LITOUT|PASS8)) {
372  cflag |= CS8;
373  if (!(flags&(RAW|PASS8))
374  || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
375  iflag |= ISTRIP;
376  else
377  iflag &= ~ISTRIP;
378  if (flags&(RAW|LITOUT))
379  oflag &= ~OPOST;
380  else
381  oflag |= OPOST;
382  } else {
383  cflag |= CS7|PARENB;
384  iflag |= ISTRIP;
385  oflag |= OPOST;
386  }
387  /* XXX don't set INPCK if RAW or PASS8? */
388  if ((flags&(EVENP|ODDP)) == EVENP) {
389  iflag |= INPCK;
390  cflag &= ~PARODD;
391  } else if ((flags&(EVENP|ODDP)) == ODDP) {
392  iflag |= INPCK;
393  cflag |= PARODD;
394  } else
395  iflag &= ~INPCK;
396  if (flags&TANDEM)
397  iflag |= IXOFF;
398  else
399  iflag &= ~IXOFF;
400  if ((flags&DECCTQ) == 0)
401  iflag |= IXANY;
402  else
403  iflag &= ~IXANY;
404  t->c_iflag = iflag;
405  t->c_oflag = oflag;
406  t->c_lflag = lflag;
407  t->c_cflag = cflag;
408 }
409 
410 static void
411 ttcompatsetlflags(struct tty *tp, struct termios *t)
412 {
413  int flags = tp->t_compatflags;
414  tcflag_t iflag = t->c_iflag;
415  tcflag_t oflag = t->c_oflag;
416  tcflag_t lflag = t->c_lflag;
417  tcflag_t cflag = t->c_cflag;
418 
419  iflag &= ~(PARMRK|IGNPAR|IGNCR|INLCR);
420  if (flags&CRTERA)
421  lflag |= ECHOE;
422  else
423  lflag &= ~ECHOE;
424  if (flags&CRTKIL)
425  lflag |= ECHOKE;
426  else
427  lflag &= ~ECHOKE;
428  if (flags&PRTERA)
429  lflag |= ECHOPRT;
430  else
431  lflag &= ~ECHOPRT;
432  if (flags&CTLECH)
433  lflag |= ECHOCTL;
434  else
435  lflag &= ~ECHOCTL;
436  if (flags&TANDEM)
437  iflag |= IXOFF;
438  else
439  iflag &= ~IXOFF;
440  if ((flags&DECCTQ) == 0)
441  iflag |= IXANY;
442  else
443  iflag &= ~IXANY;
444  if (flags & MDMBUF)
445  cflag |= MDMBUF;
446  else
447  cflag &= ~MDMBUF;
448  if (flags&NOHANG)
449  cflag &= ~HUPCL;
450  else
451  cflag |= HUPCL;
452  lflag &= ~(TOSTOP|FLUSHO|PENDIN|NOFLSH);
453  lflag |= flags&(TOSTOP|FLUSHO|PENDIN|NOFLSH);
454 
455  /*
456  * The next if-else statement is copied from above so don't bother
457  * checking it separately. We could avoid fiddlling with the
458  * character size if the mode is already RAW or if neither the
459  * LITOUT bit or the PASS8 bit is being changed, but the delta of
460  * the change is not available here and skipping the RAW case would
461  * make the code different from above.
462  */
463  cflag &= ~(CSIZE|PARENB);
464  if (flags&(RAW|LITOUT|PASS8)) {
465  cflag |= CS8;
466  if (!(flags&(RAW|PASS8))
467  || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
468  iflag |= ISTRIP;
469  else
470  iflag &= ~ISTRIP;
471  if (flags&(RAW|LITOUT))
472  oflag &= ~OPOST;
473  else
474  oflag |= OPOST;
475  } else {
476  cflag |= CS7|PARENB;
477  iflag |= ISTRIP;
478  oflag |= OPOST;
479  }
480  t->c_iflag = iflag;
481  t->c_oflag = oflag;
482  t->c_lflag = lflag;
483  t->c_cflag = cflag;
484 }
static void ttcompatsetlflags(struct tty *tp, struct termios *t)
Definition: tty_compat.c:411
int sp_code
Definition: tty_compat.c:50
static int ttsetcompat(struct tty *tp, u_long *com, caddr_t data, struct termios *term)
Definition: tty_compat.c:100
#define MAX_SPEED
static int ttcompatgetflags(struct tty *tp)
Definition: tty_compat.c:274
static struct speedtab compatspeeds[]
Definition: tty_compat.c:61
SYSCTL_INT(_debug, OID_AUTO, ttydebug, CTLFLAG_RW,&ttydebug, 0,"")
static int ttcompatspeedtab(int speed, struct speedtab *table)
Definition: tty_compat.c:89
int tty_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, struct thread *td)
Definition: tty.c:1741
int sp_speed
Definition: tty_compat.c:49
int printf(const char *fmt,...)
Definition: subr_prf.c:367
static int ttydebug
Definition: tty_compat.c:58
static int compatspcodes[]
Definition: tty_compat.c:83
static void ttcompatsetflags(struct tty *tp, struct termios *t)
Definition: tty_compat.c:334
__FBSDID("$BSDSUniX$")
int tty_ioctl_compat(struct tty *tp, u_long com, caddr_t data, int fflag, struct thread *td)
Definition: tty_compat.c:183