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