FreeBSD/Linux Kernel Cross Reference
sys/drivers/tty/tty.c
1 /* This file contains the terminal driver, both for the IBM console and regular
2 * ASCII terminals. It handles only the device-independent part of a TTY, the
3 * device dependent parts are in console.c, rs232.c, etc. This file contains
4 * two main entry points, tty_task() and tty_wakeup(), and several minor entry
5 * points for use by the device-dependent code.
6 *
7 * The device-independent part accepts "keyboard" input from the device-
8 * dependent part, performs input processing (special key interpretation),
9 * and sends the input to a process reading from the TTY. Output to a TTY
10 * is sent to the device-dependent code for output processing and "screen"
11 * display. Input processing is done by the device by calling 'in_process'
12 * on the input characters, output processing may be done by the device itself
13 * or by calling 'out_process'. The TTY takes care of input queuing, the
14 * device does the output queuing. If a device receives an external signal,
15 * like an interrupt, then it causes tty_wakeup() to be run by the CLOCK task
16 * to, you guessed it, wake up the TTY to check if input or output can
17 * continue.
18 *
19 * The valid messages and their parameters are:
20 *
21 * HARD_INT: output has been completed or input has arrived
22 * SYS_SIG: e.g., MINIX wants to shutdown; run code to cleanly stop
23 * DEV_READ: a process wants to read from a terminal
24 * DEV_WRITE: a process wants to write on a terminal
25 * DEV_IOCTL: a process wants to change a terminal's parameters
26 * DEV_OPEN: a tty line has been opened
27 * DEV_CLOSE: a tty line has been closed
28 * DEV_SELECT: start select notification request
29 * DEV_STATUS: FS wants to know status for SELECT or REVIVE
30 * CANCEL: terminate a previous incomplete system call immediately
31 *
32 * m_type TTY_LINE PROC_NR COUNT TTY_SPEK TTY_FLAGS ADDRESS
33 * ---------------------------------------------------------------------------
34 * | HARD_INT | | | | | | |
35 * |-------------+---------+---------+---------+---------+---------+---------|
36 * | SYS_SIG | sig set | | | | | |
37 * |-------------+---------+---------+---------+---------+---------+---------|
38 * | DEV_READ |minor dev| proc nr | count | O_NONBLOCK| buf ptr |
39 * |-------------+---------+---------+---------+---------+---------+---------|
40 * | DEV_WRITE |minor dev| proc nr | count | | | buf ptr |
41 * |-------------+---------+---------+---------+---------+---------+---------|
42 * | DEV_IOCTL |minor dev| proc nr |func code|erase etc| flags | |
43 * |-------------+---------+---------+---------+---------+---------+---------|
44 * | DEV_OPEN |minor dev| proc nr | O_NOCTTY| | | |
45 * |-------------+---------+---------+---------+---------+---------+---------|
46 * | DEV_CLOSE |minor dev| proc nr | | | | |
47 * |-------------+---------+---------+---------+---------+---------+---------|
48 * | DEV_SELECT | | | | | | |
49 * |-------------+---------+---------+---------+---------+---------+---------|
50 * | DEV_STATUS | | | | | | |
51 * |-------------+---------+---------+---------+---------+---------+---------|
52 * | CANCEL |minor dev| proc nr | | | | |
53 * ---------------------------------------------------------------------------
54 *
55 * Changes:
56 * Jan 20, 2004 moved TTY driver to user-space (Jorrit N. Herder)
57 * Sep 20, 2004 local timer management/ sync alarms (Jorrit N. Herder)
58 * Jul 13, 2004 support for function key observers (Jorrit N. Herder)
59 */
60
61 #include "../drivers.h"
62 #include <termios.h>
63 #if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
64 #include <sgtty.h>
65 #endif
66 #include <sys/ioc_tty.h>
67 #include <signal.h>
68 #include <minix/callnr.h>
69 #if (CHIP == INTEL)
70 #include <minix/keymap.h>
71 #endif
72 #include "tty.h"
73
74 #include <sys/time.h>
75 #include <sys/select.h>
76
77 extern int irq_hook_id;
78
79 unsigned long kbd_irq_set = 0;
80 unsigned long rs_irq_set = 0;
81
82 /* Address of a tty structure. */
83 #define tty_addr(line) (&tty_table[line])
84
85 /* Macros for magic tty types. */
86 #define isconsole(tp) ((tp) < tty_addr(NR_CONS))
87 #define ispty(tp) ((tp) >= tty_addr(NR_CONS+NR_RS_LINES))
88
89 /* Macros for magic tty structure pointers. */
90 #define FIRST_TTY tty_addr(0)
91 #define END_TTY tty_addr(sizeof(tty_table) / sizeof(tty_table[0]))
92
93 /* A device exists if at least its 'devread' function is defined. */
94 #define tty_active(tp) ((tp)->tty_devread != NULL)
95
96 /* RS232 lines or pseudo terminals can be completely configured out. */
97 #if NR_RS_LINES == 0
98 #define rs_init(tp) ((void) 0)
99 #endif
100 #if NR_PTYS == 0
101 #define pty_init(tp) ((void) 0)
102 #define do_pty(tp, mp) ((void) 0)
103 #endif
104
105 struct kmessages kmess;
106
107 FORWARD _PROTOTYPE( void tty_timed_out, (timer_t *tp) );
108 FORWARD _PROTOTYPE( void expire_timers, (void) );
109 FORWARD _PROTOTYPE( void settimer, (tty_t *tty_ptr, int enable) );
110 FORWARD _PROTOTYPE( void do_cancel, (tty_t *tp, message *m_ptr) );
111 FORWARD _PROTOTYPE( void do_ioctl, (tty_t *tp, message *m_ptr) );
112 FORWARD _PROTOTYPE( void do_open, (tty_t *tp, message *m_ptr) );
113 FORWARD _PROTOTYPE( void do_close, (tty_t *tp, message *m_ptr) );
114 FORWARD _PROTOTYPE( void do_read, (tty_t *tp, message *m_ptr) );
115 FORWARD _PROTOTYPE( void do_write, (tty_t *tp, message *m_ptr) );
116 FORWARD _PROTOTYPE( void do_select, (tty_t *tp, message *m_ptr) );
117 FORWARD _PROTOTYPE( void do_status, (message *m_ptr) );
118 FORWARD _PROTOTYPE( void in_transfer, (tty_t *tp) );
119 FORWARD _PROTOTYPE( int tty_echo, (tty_t *tp, int ch) );
120 FORWARD _PROTOTYPE( void rawecho, (tty_t *tp, int ch) );
121 FORWARD _PROTOTYPE( int back_over, (tty_t *tp) );
122 FORWARD _PROTOTYPE( void reprint, (tty_t *tp) );
123 FORWARD _PROTOTYPE( void dev_ioctl, (tty_t *tp) );
124 FORWARD _PROTOTYPE( void setattr, (tty_t *tp) );
125 FORWARD _PROTOTYPE( void tty_icancel, (tty_t *tp) );
126 FORWARD _PROTOTYPE( void tty_init, (void) );
127 #if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
128 FORWARD _PROTOTYPE( int compat_getp, (tty_t *tp, struct sgttyb *sg) );
129 FORWARD _PROTOTYPE( int compat_getc, (tty_t *tp, struct tchars *sg) );
130 FORWARD _PROTOTYPE( int compat_setp, (tty_t *tp, struct sgttyb *sg) );
131 FORWARD _PROTOTYPE( int compat_setc, (tty_t *tp, struct tchars *sg) );
132 FORWARD _PROTOTYPE( int tspd2sgspd, (speed_t tspd) );
133 FORWARD _PROTOTYPE( speed_t sgspd2tspd, (int sgspd) );
134 #if ENABLE_BINCOMPAT
135 FORWARD _PROTOTYPE( void do_ioctl_compat, (tty_t *tp, message *m_ptr) );
136 #endif
137 #endif
138
139 /* Default attributes. */
140 PRIVATE struct termios termios_defaults = {
141 TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF, TSPEED_DEF, TSPEED_DEF,
142 {
143 TEOF_DEF, TEOL_DEF, TERASE_DEF, TINTR_DEF, TKILL_DEF, TMIN_DEF,
144 TQUIT_DEF, TTIME_DEF, TSUSP_DEF, TSTART_DEF, TSTOP_DEF,
145 TREPRINT_DEF, TLNEXT_DEF, TDISCARD_DEF,
146 },
147 };
148 PRIVATE struct winsize winsize_defaults; /* = all zeroes */
149
150 /* Global variables for the TTY task (declared extern in tty.h). */
151 PUBLIC tty_t tty_table[NR_CONS+NR_RS_LINES+NR_PTYS];
152 PUBLIC int ccurrent; /* currently active console */
153 PUBLIC timer_t *tty_timers; /* queue of TTY timers */
154 PUBLIC clock_t tty_next_timeout; /* time that the next alarm is due */
155 PUBLIC struct machine machine; /* kernel environment variables */
156
157 /*===========================================================================*
158 * tty_task *
159 *===========================================================================*/
160 PUBLIC void main(void)
161 {
162 /* Main routine of the terminal task. */
163
164 message tty_mess; /* buffer for all incoming messages */
165 unsigned line;
166 int r, s;
167 register struct proc *rp;
168 register tty_t *tp;
169
170 /* Initialize the TTY driver. */
171 tty_init();
172
173 /* Get kernel environment (protected_mode, pc_at and ega are needed). */
174 if (OK != (s=sys_getmachine(&machine))) {
175 panic("TTY","Couldn't obtain kernel environment.", s);
176 }
177
178 /* Final one-time keyboard initialization. */
179 kb_init_once();
180
181 printf("\n");
182
183 while (TRUE) {
184
185 /* Check for and handle any events on any of the ttys. */
186 for (tp = FIRST_TTY; tp < END_TTY; tp++) {
187 if (tp->tty_events) handle_events(tp);
188 }
189
190 /* Get a request message. */
191 r= receive(ANY, &tty_mess);
192 if (r != 0)
193 panic("TTY", "receive failed with %d", r);
194
195 /* First handle all kernel notification types that the TTY supports.
196 * - An alarm went off, expire all timers and handle the events.
197 * - A hardware interrupt also is an invitation to check for events.
198 * - A new kernel message is available for printing.
199 * - Reset the console on system shutdown.
200 * Then see if this message is different from a normal device driver
201 * request and should be handled separately. These extra functions
202 * do not operate on a device, in constrast to the driver requests.
203 */
204 switch (tty_mess.m_type) {
205 case SYN_ALARM: /* fall through */
206 expire_timers(); /* run watchdogs of expired timers */
207 continue; /* contine to check for events */
208 case DEV_PING:
209 notify(tty_mess.m_source);
210 continue;
211 case HARD_INT: { /* hardware interrupt notification */
212 if (tty_mess.NOTIFY_ARG & kbd_irq_set)
213 kbd_interrupt(&tty_mess);/* fetch chars from keyboard */
214 #if NR_RS_LINES > 0
215 if (tty_mess.NOTIFY_ARG & rs_irq_set)
216 rs_interrupt(&tty_mess);/* serial I/O */
217 #endif
218 expire_timers(); /* run watchdogs of expired timers */
219 continue; /* contine to check for events */
220 }
221 case SYS_SIG: { /* system signal */
222 sigset_t sigset = (sigset_t) tty_mess.NOTIFY_ARG;
223
224 if (sigismember(&sigset, SIGKSTOP)) {
225 cons_stop(); /* switch to primary console */
226 if (irq_hook_id != -1) {
227 sys_irqdisable(&irq_hook_id);
228 sys_irqrmpolicy(KEYBOARD_IRQ, &irq_hook_id);
229 }
230 }
231 if (sigismember(&sigset, SIGTERM)) cons_stop();
232 if (sigismember(&sigset, SIGKMESS)) do_new_kmess(&tty_mess);
233 continue;
234 }
235 case PANIC_DUMPS: /* allow panic dumps */
236 cons_stop(); /* switch to primary console */
237 do_panic_dumps(&tty_mess);
238 continue;
239 case DIAGNOSTICS: /* a server wants to print some */
240 do_diagnostics(&tty_mess);
241 continue;
242 case GET_KMESS:
243 do_get_kmess(&tty_mess);
244 continue;
245 case FKEY_CONTROL: /* (un)register a fkey observer */
246 do_fkey_ctl(&tty_mess);
247 continue;
248 default: /* should be a driver request */
249 ; /* do nothing; end switch */
250 }
251
252 /* Only device requests should get to this point. All requests,
253 * except DEV_STATUS, have a minor device number. Check this
254 * exception and get the minor device number otherwise.
255 */
256 if (tty_mess.m_type == DEV_STATUS) {
257 do_status(&tty_mess);
258 continue;
259 }
260 line = tty_mess.TTY_LINE;
261 if ((line - CONS_MINOR) < NR_CONS) {
262 tp = tty_addr(line - CONS_MINOR);
263 } else if (line == LOG_MINOR) {
264 tp = tty_addr(0);
265 } else if ((line - RS232_MINOR) < NR_RS_LINES) {
266 tp = tty_addr(line - RS232_MINOR + NR_CONS);
267 } else if ((line - TTYPX_MINOR) < NR_PTYS) {
268 tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
269 } else if ((line - PTYPX_MINOR) < NR_PTYS) {
270 tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
271 if (tty_mess.m_type != DEV_IOCTL) {
272 do_pty(tp, &tty_mess);
273 continue;
274 }
275 } else {
276 tp = NULL;
277 }
278
279 /* If the device doesn't exist or is not configured return ENXIO. */
280 if (tp == NULL || ! tty_active(tp)) {
281 printf("Warning, TTY got illegal request %d from %d\n",
282 tty_mess.m_type, tty_mess.m_source);
283 if (tty_mess.m_source != LOG_PROC_NR)
284 {
285 tty_reply(TASK_REPLY, tty_mess.m_source,
286 tty_mess.PROC_NR, ENXIO);
287 }
288 continue;
289 }
290
291 /* Execute the requested device driver function. */
292 switch (tty_mess.m_type) {
293 case DEV_READ: do_read(tp, &tty_mess); break;
294 case DEV_WRITE: do_write(tp, &tty_mess); break;
295 case DEV_IOCTL: do_ioctl(tp, &tty_mess); break;
296 case DEV_OPEN: do_open(tp, &tty_mess); break;
297 case DEV_CLOSE: do_close(tp, &tty_mess); break;
298 case DEV_SELECT: do_select(tp, &tty_mess); break;
299 case CANCEL: do_cancel(tp, &tty_mess); break;
300 default:
301 printf("Warning, TTY got unexpected request %d from %d\n",
302 tty_mess.m_type, tty_mess.m_source);
303 tty_reply(TASK_REPLY, tty_mess.m_source,
304 tty_mess.PROC_NR, EINVAL);
305 }
306 }
307 }
308
309 /*===========================================================================*
310 * do_status *
311 *===========================================================================*/
312 PRIVATE void do_status(m_ptr)
313 message *m_ptr;
314 {
315 register struct tty *tp;
316 int event_found;
317 int status;
318 int ops;
319
320 /* Check for select or revive events on any of the ttys. If we found an,
321 * event return a single status message for it. The FS will make another
322 * call to see if there is more.
323 */
324 event_found = 0;
325 for (tp = FIRST_TTY; tp < END_TTY; tp++) {
326 if ((ops = select_try(tp, tp->tty_select_ops)) &&
327 tp->tty_select_proc == m_ptr->m_source) {
328
329 /* I/O for a selected minor device is ready. */
330 m_ptr->m_type = DEV_IO_READY;
331 m_ptr->DEV_MINOR = tp->tty_minor;
332 m_ptr->DEV_SEL_OPS = ops;
333
334 tp->tty_select_ops &= ~ops; /* unmark select event */
335 event_found = 1;
336 break;
337 }
338 else if (tp->tty_inrevived && tp->tty_incaller == m_ptr->m_source) {
339
340 /* Suspended request finished. Send a REVIVE. */
341 m_ptr->m_type = DEV_REVIVE;
342 m_ptr->REP_PROC_NR = tp->tty_inproc;
343 m_ptr->REP_STATUS = tp->tty_incum;
344
345 tp->tty_inleft = tp->tty_incum = 0;
346 tp->tty_inrevived = 0; /* unmark revive event */
347 event_found = 1;
348 break;
349 }
350 else if (tp->tty_outrevived && tp->tty_outcaller == m_ptr->m_source) {
351
352 /* Suspended request finished. Send a REVIVE. */
353 m_ptr->m_type = DEV_REVIVE;
354 m_ptr->REP_PROC_NR = tp->tty_outproc;
355 m_ptr->REP_STATUS = tp->tty_outcum;
356
357 tp->tty_outcum = 0;
358 tp->tty_outrevived = 0; /* unmark revive event */
359 event_found = 1;
360 break;
361 }
362 }
363
364 #if NR_PTYS > 0
365 if (!event_found)
366 event_found = pty_status(m_ptr);
367 #endif
368
369 if (! event_found) {
370 /* No events of interest were found. Return an empty message. */
371 m_ptr->m_type = DEV_NO_STATUS;
372 }
373
374 /* Almost done. Send back the reply message to the caller. */
375 if ((status = send(m_ptr->m_source, m_ptr)) != OK) {
376 panic("TTY","send in do_status failed, status\n", status);
377 }
378 }
379
380 /*===========================================================================*
381 * do_read *
382 *===========================================================================*/
383 PRIVATE void do_read(tp, m_ptr)
384 register tty_t *tp; /* pointer to tty struct */
385 register message *m_ptr; /* pointer to message sent to the task */
386 {
387 /* A process wants to read from a terminal. */
388 int r, status;
389 phys_bytes phys_addr;
390
391 /* Check if there is already a process hanging in a read, check if the
392 * parameters are correct, do I/O.
393 */
394 if (tp->tty_inleft > 0) {
395 r = EIO;
396 } else
397 if (m_ptr->COUNT <= 0) {
398 r = EINVAL;
399 } else
400 if (sys_umap(m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,
401 &phys_addr) != OK) {
402 r = EFAULT;
403 } else {
404 /* Copy information from the message to the tty struct. */
405 tp->tty_inrepcode = TASK_REPLY;
406 tp->tty_incaller = m_ptr->m_source;
407 tp->tty_inproc = m_ptr->PROC_NR;
408 tp->tty_in_vir = (vir_bytes) m_ptr->ADDRESS;
409 tp->tty_inleft = m_ptr->COUNT;
410
411 if (!(tp->tty_termios.c_lflag & ICANON)
412 && tp->tty_termios.c_cc[VTIME] > 0) {
413 if (tp->tty_termios.c_cc[VMIN] == 0) {
414 /* MIN & TIME specify a read timer that finishes the
415 * read in TIME/10 seconds if no bytes are available.
416 */
417 settimer(tp, TRUE);
418 tp->tty_min = 1;
419 } else {
420 /* MIN & TIME specify an inter-byte timer that may
421 * have to be cancelled if there are no bytes yet.
422 */
423 if (tp->tty_eotct == 0) {
424 settimer(tp, FALSE);
425 tp->tty_min = tp->tty_termios.c_cc[VMIN];
426 }
427 }
428 }
429
430 /* Anything waiting in the input buffer? Clear it out... */
431 in_transfer(tp);
432 /* ...then go back for more. */
433 handle_events(tp);
434 if (tp->tty_inleft == 0) {
435 if (tp->tty_select_ops)
436 select_retry(tp);
437 return; /* already done */
438 }
439
440 /* There were no bytes in the input queue available, so either suspend
441 * the caller or break off the read if nonblocking.
442 */
443 if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
444 r = EAGAIN; /* cancel the read */
445 tp->tty_inleft = tp->tty_incum = 0;
446 } else {
447 r = SUSPEND; /* suspend the caller */
448 tp->tty_inrepcode = REVIVE;
449 }
450 }
451 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
452 if (tp->tty_select_ops)
453 select_retry(tp);
454 }
455
456 /*===========================================================================*
457 * do_write *
458 *===========================================================================*/
459 PRIVATE void do_write(tp, m_ptr)
460 register tty_t *tp;
461 register message *m_ptr; /* pointer to message sent to the task */
462 {
463 /* A process wants to write on a terminal. */
464 int r;
465 phys_bytes phys_addr;
466
467 /* Check if there is already a process hanging in a write, check if the
468 * parameters are correct, do I/O.
469 */
470 if (tp->tty_outleft > 0) {
471 r = EIO;
472 } else
473 if (m_ptr->COUNT <= 0) {
474 r = EINVAL;
475 } else
476 if (sys_umap(m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,
477 &phys_addr) != OK) {
478 r = EFAULT;
479 } else {
480 /* Copy message parameters to the tty structure. */
481 tp->tty_outrepcode = TASK_REPLY;
482 tp->tty_outcaller = m_ptr->m_source;
483 tp->tty_outproc = m_ptr->PROC_NR;
484 tp->tty_out_vir = (vir_bytes) m_ptr->ADDRESS;
485 tp->tty_outleft = m_ptr->COUNT;
486
487 /* Try to write. */
488 handle_events(tp);
489 if (tp->tty_outleft == 0)
490 return; /* already done */
491
492 /* None or not all the bytes could be written, so either suspend the
493 * caller or break off the write if nonblocking.
494 */
495 if (m_ptr->TTY_FLAGS & O_NONBLOCK) { /* cancel the write */
496 r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
497 tp->tty_outleft = tp->tty_outcum = 0;
498 } else {
499 r = SUSPEND; /* suspend the caller */
500 tp->tty_outrepcode = REVIVE;
501 }
502 }
503 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
504 }
505
506 /*===========================================================================*
507 * do_ioctl *
508 *===========================================================================*/
509 PRIVATE void do_ioctl(tp, m_ptr)
510 register tty_t *tp;
511 message *m_ptr; /* pointer to message sent to task */
512 {
513 /* Perform an IOCTL on this terminal. Posix termios calls are handled
514 * by the IOCTL system call
515 */
516
517 int r;
518 union {
519 int i;
520 #if ENABLE_SRCCOMPAT
521 struct sgttyb sg;
522 struct tchars tc;
523 #endif
524 } param;
525 size_t size;
526
527 /* Size of the ioctl parameter. */
528 switch (m_ptr->TTY_REQUEST) {
529 case TCGETS: /* Posix tcgetattr function */
530 case TCSETS: /* Posix tcsetattr function, TCSANOW option */
531 case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */
532 case TCSETSF: /* Posix tcsetattr function, TCSAFLUSH option */
533 size = sizeof(struct termios);
534 break;
535
536 case TCSBRK: /* Posix tcsendbreak function */
537 case TCFLOW: /* Posix tcflow function */
538 case TCFLSH: /* Posix tcflush function */
539 case TIOCGPGRP: /* Posix tcgetpgrp function */
540 case TIOCSPGRP: /* Posix tcsetpgrp function */
541 size = sizeof(int);
542 break;
543
544 case TIOCGWINSZ: /* get window size (not Posix) */
545 case TIOCSWINSZ: /* set window size (not Posix) */
546 size = sizeof(struct winsize);
547 break;
548
549 #if ENABLE_SRCCOMPAT
550 case TIOCGETP: /* BSD-style get terminal properties */
551 case TIOCSETP: /* BSD-style set terminal properties */
552 size = sizeof(struct sgttyb);
553 break;
554
555 case TIOCGETC: /* BSD-style get terminal special characters */
556 case TIOCSETC: /* BSD-style get terminal special characters */
557 size = sizeof(struct tchars);
558 break;
559 #endif
560 #if (MACHINE == IBM_PC)
561 case KIOCSMAP: /* load keymap (Minix extension) */
562 size = sizeof(keymap_t);
563 break;
564
565 case TIOCSFON: /* load font (Minix extension) */
566 size = sizeof(u8_t [8192]);
567 break;
568
569 #endif
570 case TCDRAIN: /* Posix tcdrain function -- no parameter */
571 default: size = 0;
572 }
573
574 r = OK;
575 switch (m_ptr->TTY_REQUEST) {
576 case TCGETS:
577 /* Get the termios attributes. */
578 r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_termios,
579 m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
580 (vir_bytes) size);
581 break;
582
583 case TCSETSW:
584 case TCSETSF:
585 case TCDRAIN:
586 if (tp->tty_outleft > 0) {
587 /* Wait for all ongoing output processing to finish. */
588 tp->tty_iocaller = m_ptr->m_source;
589 tp->tty_ioproc = m_ptr->PROC_NR;
590 tp->tty_ioreq = m_ptr->REQUEST;
591 tp->tty_iovir = (vir_bytes) m_ptr->ADDRESS;
592 r = SUSPEND;
593 break;
594 }
595 if (m_ptr->TTY_REQUEST == TCDRAIN) break;
596 if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp);
597 /*FALL THROUGH*/
598 case TCSETS:
599 /* Set the termios attributes. */
600 r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
601 SELF, D, (vir_bytes) &tp->tty_termios, (vir_bytes) size);
602 if (r != OK) break;
603 setattr(tp);
604 break;
605
606 case TCFLSH:
607 r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
608 SELF, D, (vir_bytes) ¶m.i, (vir_bytes) size);
609 if (r != OK) break;
610 switch (param.i) {
611 case TCIFLUSH: tty_icancel(tp); break;
612 case TCOFLUSH: (*tp->tty_ocancel)(tp, 0); break;
613 case TCIOFLUSH: tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); break;
614 default: r = EINVAL;
615 }
616 break;
617
618 case TCFLOW:
619 r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
620 SELF, D, (vir_bytes) ¶m.i, (vir_bytes) size);
621 if (r != OK) break;
622 switch (param.i) {
623 case TCOOFF:
624 case TCOON:
625 tp->tty_inhibited = (param.i == TCOOFF);
626 tp->tty_events = 1;
627 break;
628 case TCIOFF:
629 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTOP]);
630 break;
631 case TCION:
632 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTART]);
633 break;
634 default:
635 r = EINVAL;
636 }
637 break;
638
639 case TCSBRK:
640 if (tp->tty_break != NULL) (*tp->tty_break)(tp,0);
641 break;
642
643 case TIOCGWINSZ:
644 r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_winsize,
645 m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
646 (vir_bytes) size);
647 break;
648
649 case TIOCSWINSZ:
650 r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
651 SELF, D, (vir_bytes) &tp->tty_winsize, (vir_bytes) size);
652 sigchar(tp, SIGWINCH);
653 break;
654
655 #if ENABLE_SRCCOMPAT
656 case TIOCGETP:
657 compat_getp(tp, ¶m.sg);
658 r = sys_vircopy(SELF, D, (vir_bytes) ¶m.sg,
659 m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
660 (vir_bytes) size);
661 break;
662
663 case TIOCSETP:
664 r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
665 SELF, D, (vir_bytes) ¶m.sg, (vir_bytes) size);
666 if (r != OK) break;
667 compat_setp(tp, ¶m.sg);
668 break;
669
670 case TIOCGETC:
671 compat_getc(tp, ¶m.tc);
672 r = sys_vircopy(SELF, D, (vir_bytes) ¶m.tc,
673 m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
674 (vir_bytes) size);
675 break;
676
677 case TIOCSETC:
678 r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
679 SELF, D, (vir_bytes) ¶m.tc, (vir_bytes) size);
680 if (r != OK) break;
681 compat_setc(tp, ¶m.tc);
682 break;
683 #endif
684
685 #if (MACHINE == IBM_PC)
686 case KIOCSMAP:
687 /* Load a new keymap (only /dev/console). */
688 if (isconsole(tp)) r = kbd_loadmap(m_ptr);
689 break;
690
691 case TIOCSFON:
692 /* Load a font into an EGA or VGA card (hs@hck.hr) */
693 if (isconsole(tp)) r = con_loadfont(m_ptr);
694 break;
695 #endif
696
697 #if (MACHINE == ATARI)
698 case VDU_LOADFONT:
699 r = vdu_loadfont(m_ptr);
700 break;
701 #endif
702
703 /* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is
704 * not defined.
705 */
706 case TIOCGPGRP:
707 case TIOCSPGRP:
708 default:
709 #if ENABLE_BINCOMPAT
710 do_ioctl_compat(tp, m_ptr);
711 return;
712 #else
713 r = ENOTTY;
714 #endif
715 }
716
717 /* Send the reply. */
718 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
719 }
720
721 /*===========================================================================*
722 * do_open *
723 *===========================================================================*/
724 PRIVATE void do_open(tp, m_ptr)
725 register tty_t *tp;
726 message *m_ptr; /* pointer to message sent to task */
727 {
728 /* A tty line has been opened. Make it the callers controlling tty if
729 * O_NOCTTY is *not* set and it is not the log device. 1 is returned if
730 * the tty is made the controlling tty, otherwise OK or an error code.
731 */
732 int r = OK;
733
734 if (m_ptr->TTY_LINE == LOG_MINOR) {
735 /* The log device is a write-only diagnostics device. */
736 if (m_ptr->COUNT & R_BIT) r = EACCES;
737 } else {
738 if (!(m_ptr->COUNT & O_NOCTTY)) {
739 tp->tty_pgrp = m_ptr->PROC_NR;
740 r = 1;
741 }
742 tp->tty_openct++;
743 }
744 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
745 }
746
747 /*===========================================================================*
748 * do_close *
749 *===========================================================================*/
750 PRIVATE void do_close(tp, m_ptr)
751 register tty_t *tp;
752 message *m_ptr; /* pointer to message sent to task */
753 {
754 /* A tty line has been closed. Clean up the line if it is the last close. */
755
756 if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) {
757 tp->tty_pgrp = 0;
758 tty_icancel(tp);
759 (*tp->tty_ocancel)(tp, 0);
760 (*tp->tty_close)(tp, 0);
761 tp->tty_termios = termios_defaults;
762 tp->tty_winsize = winsize_defaults;
763 setattr(tp);
764 }
765 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK);
766 }
767
768 /*===========================================================================*
769 * do_cancel *
770 *===========================================================================*/
771 PRIVATE void do_cancel(tp, m_ptr)
772 register tty_t *tp;
773 message *m_ptr; /* pointer to message sent to task */
774 {
775 /* A signal has been sent to a process that is hanging trying to read or write.
776 * The pending read or write must be finished off immediately.
777 */
778
779 int proc_nr;
780 int mode;
781
782 /* Check the parameters carefully, to avoid cancelling twice. */
783 proc_nr = m_ptr->PROC_NR;
784 mode = m_ptr->COUNT;
785 if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc) {
786 /* Process was reading when killed. Clean up input. */
787 tty_icancel(tp);
788 tp->tty_inleft = tp->tty_incum = 0;
789 }
790 if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc) {
791 /* Process was writing when killed. Clean up output. */
792 (*tp->tty_ocancel)(tp, 0);
793 tp->tty_outleft = tp->tty_outcum = 0;
794 }
795 if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
796 /* Process was waiting for output to drain. */
797 tp->tty_ioreq = 0;
798 }
799 tp->tty_events = 1;
800 tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, EINTR);
801 }
802
803 PUBLIC int select_try(struct tty *tp, int ops)
804 {
805 int ready_ops = 0;
806
807 /* Special case. If line is hung up, no operations will block.
808 * (and it can be seen as an exceptional condition.)
809 */
810 if (tp->tty_termios.c_ospeed == B0) {
811 ready_ops |= ops;
812 }
813
814 if (ops & SEL_RD) {
815 /* will i/o not block on read? */
816 if (tp->tty_inleft > 0) {
817 ready_ops |= SEL_RD; /* EIO - no blocking */
818 } else if (tp->tty_incount > 0) {
819 /* Is a regular read possible? tty_incount
820 * says there is data. But a read will only succeed
821 * in canonical mode if a newline has been seen.
822 */
823 if (!(tp->tty_termios.c_lflag & ICANON) ||
824 tp->tty_eotct > 0) {
825 ready_ops |= SEL_RD;
826 }
827 }
828 }
829
830 if (ops & SEL_WR) {
831 if (tp->tty_outleft > 0) ready_ops |= SEL_WR;
832 else if ((*tp->tty_devwrite)(tp, 1)) ready_ops |= SEL_WR;
833 }
834
835 return ready_ops;
836 }
837
838 PUBLIC int select_retry(struct tty *tp)
839 {
840 if (select_try(tp, tp->tty_select_ops))
841 notify(tp->tty_select_proc);
842 return OK;
843 }
844
845 /*===========================================================================*
846 * handle_events *
847 *===========================================================================*/
848 PUBLIC void handle_events(tp)
849 tty_t *tp; /* TTY to check for events. */
850 {
851 /* Handle any events pending on a TTY. These events are usually device
852 * interrupts.
853 *
854 * Two kinds of events are prominent:
855 * - a character has been received from the console or an RS232 line.
856 * - an RS232 line has completed a write request (on behalf of a user).
857 * The interrupt handler may delay the interrupt message at its discretion
858 * to avoid swamping the TTY task. Messages may be overwritten when the
859 * lines are fast or when there are races between different lines, input
860 * and output, because MINIX only provides single buffering for interrupt
861 * messages (in proc.c). This is handled by explicitly checking each line
862 * for fresh input and completed output on each interrupt.
863 */
864 char *buf;
865 unsigned count;
866 int status;
867
868 do {
869 tp->tty_events = 0;
870
871 /* Read input and perform input processing. */
872 (*tp->tty_devread)(tp, 0);
873
874 /* Perform output processing and write output. */
875 (*tp->tty_devwrite)(tp, 0);
876
877 /* Ioctl waiting for some event? */
878 if (tp->tty_ioreq != 0) dev_ioctl(tp);
879 } while (tp->tty_events);
880
881 /* Transfer characters from the input queue to a waiting process. */
882 in_transfer(tp);
883
884 /* Reply if enough bytes are available. */
885 if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
886 if (tp->tty_inrepcode == REVIVE) {
887 notify(tp->tty_incaller);
888 tp->tty_inrevived = 1;
889 } else {
890 tty_reply(tp->tty_inrepcode, tp->tty_incaller,
891 tp->tty_inproc, tp->tty_incum);
892 tp->tty_inleft = tp->tty_incum = 0;
893 }
894 }
895 if (tp->tty_select_ops)
896 select_retry(tp);
897 #if NR_PTYS > 0
898 if (ispty(tp))
899 select_retry_pty(tp);
900 #endif
901 }
902
903 /*===========================================================================*
904 * in_transfer *
905 *===========================================================================*/
906 PRIVATE void in_transfer(tp)
907 register tty_t *tp; /* pointer to terminal to read from */
908 {
909 /* Transfer bytes from the input queue to a process reading from a terminal. */
910
911 int ch;
912 int count;
913 char buf[64], *bp;
914
915 /* Force read to succeed if the line is hung up, looks like EOF to reader. */
916 if (tp->tty_termios.c_ospeed == B0) tp->tty_min = 0;
917
918 /* Anything to do? */
919 if (tp->tty_inleft == 0 || tp->tty_eotct < tp->tty_min) return;
920
921 bp = buf;
922 while (tp->tty_inleft > 0 && tp->tty_eotct > 0) {
923 ch = *tp->tty_intail;
924
925 if (!(ch & IN_EOF)) {
926 /* One character to be delivered to the user. */
927 *bp = ch & IN_CHAR;
928 tp->tty_inleft--;
929 if (++bp == bufend(buf)) {
930 /* Temp buffer full, copy to user space. */
931 sys_vircopy(SELF, D, (vir_bytes) buf,
932 tp->tty_inproc, D, tp->tty_in_vir,
933 (vir_bytes) buflen(buf));
934 tp->tty_in_vir += buflen(buf);
935 tp->tty_incum += buflen(buf);
936 bp = buf;
937 }
938 }
939
940 /* Remove the character from the input queue. */
941 if (++tp->tty_intail == bufend(tp->tty_inbuf))
942 tp->tty_intail = tp->tty_inbuf;
943 tp->tty_incount--;
944 if (ch & IN_EOT) {
945 tp->tty_eotct--;
946 /* Don't read past a line break in canonical mode. */
947 if (tp->tty_termios.c_lflag & ICANON) tp->tty_inleft = 0;
948 }
949 }
950
951 if (bp > buf) {
952 /* Leftover characters in the buffer. */
953 count = bp - buf;
954 sys_vircopy(SELF, D, (vir_bytes) buf,
955 tp->tty_inproc, D, tp->tty_in_vir, (vir_bytes) count);
956 tp->tty_in_vir += count;
957 tp->tty_incum += count;
958 }
959
960 /* Usually reply to the reader, possibly even if incum == 0 (EOF). */
961 if (tp->tty_inleft == 0) {
962 if (tp->tty_inrepcode == REVIVE) {
963 notify(tp->tty_incaller);
964 tp->tty_inrevived = 1;
965 } else {
966 tty_reply(tp->tty_inrepcode, tp->tty_incaller,
967 tp->tty_inproc, tp->tty_incum);
968 tp->tty_inleft = tp->tty_incum = 0;
969 }
970 }
971 }
972
973 /*===========================================================================*
974 * in_process *
975 *===========================================================================*/
976 PUBLIC int in_process(tp, buf, count)
977 register tty_t *tp; /* terminal on which character has arrived */
978 char *buf; /* buffer with input characters */
979 int count; /* number of input characters */
980 {
981 /* Characters have just been typed in. Process, save, and echo them. Return
982 * the number of characters processed.
983 */
984
985 int ch, sig, ct;
986 int timeset = FALSE;
987 static unsigned char csize_mask[] = { 0x1F, 0x3F, 0x7F, 0xFF };
988
989 for (ct = 0; ct < count; ct++) {
990 /* Take one character. */
991 ch = *buf++ & BYTE;
992
993 /* Strip to seven bits? */
994 if (tp->tty_termios.c_iflag & ISTRIP) ch &= 0x7F;
995
996 /* Input extensions? */
997 if (tp->tty_termios.c_lflag & IEXTEN) {
998
999 /* Previous character was a character escape? */
1000 if (tp->tty_escaped) {
1001 tp->tty_escaped = NOT_ESCAPED;
1002 ch |= IN_ESC; /* protect character */
1003 }
1004
1005 /* LNEXT (^V) to escape the next character? */
1006 if (ch == tp->tty_termios.c_cc[VLNEXT]) {
1007 tp->tty_escaped = ESCAPED;
1008 rawecho(tp, '^');
1009 rawecho(tp, '\b');
1010 continue; /* do not store the escape */
1011 }
1012
1013 /* REPRINT (^R) to reprint echoed characters? */
1014 if (ch == tp->tty_termios.c_cc[VREPRINT]) {
1015 reprint(tp);
1016 continue;
1017 }
1018 }
1019
1020 /* _POSIX_VDISABLE is a normal character value, so better escape it. */
1021 if (ch == _POSIX_VDISABLE) ch |= IN_ESC;
1022
1023 /* Map CR to LF, ignore CR, or map LF to CR. */
1024 if (ch == '\r') {
1025 if (tp->tty_termios.c_iflag & IGNCR) continue;
1026 if (tp->tty_termios.c_iflag & ICRNL) ch = '\n';
1027 } else
1028 if (ch == '\n') {
1029 if (tp->tty_termios.c_iflag & INLCR) ch = '\r';
1030 }
1031
1032 /* Canonical mode? */
1033 if (tp->tty_termios.c_lflag & ICANON) {
1034
1035 /* Erase processing (rub out of last character). */
1036 if (ch == tp->tty_termios.c_cc[VERASE]) {
1037 (void) back_over(tp);
1038 if (!(tp->tty_termios.c_lflag & ECHOE)) {
1039 (void) tty_echo(tp, ch);
1040 }
1041 continue;
1042 }
1043
1044 /* Kill processing (remove current line). */
1045 if (ch == tp->tty_termios.c_cc[VKILL]) {
1046 while (back_over(tp)) {}
1047 if (!(tp->tty_termios.c_lflag & ECHOE)) {
1048 (void) tty_echo(tp, ch);
1049 if (tp->tty_termios.c_lflag & ECHOK)
1050 rawecho(tp, '\n');
1051 }
1052 continue;
1053 }
1054
1055 /* EOF (^D) means end-of-file, an invisible "line break". */
1056 if (ch == tp->tty_termios.c_cc[VEOF]) ch |= IN_EOT | IN_EOF;
1057
1058 /* The line may be returned to the user after an LF. */
1059 if (ch == '\n') ch |= IN_EOT;
1060
1061 /* Same thing with EOL, whatever it may be. */
1062 if (ch == tp->tty_termios.c_cc[VEOL]) ch |= IN_EOT;
1063 }
1064
1065 /* Start/stop input control? */
1066 if (tp->tty_termios.c_iflag & IXON) {
1067
1068 /* Output stops on STOP (^S). */
1069 if (ch == tp->tty_termios.c_cc[VSTOP]) {
1070 tp->tty_inhibited = STOPPED;
1071 tp->tty_events = 1;
1072 continue;
1073 }
1074
1075 /* Output restarts on START (^Q) or any character if IXANY. */
1076 if (tp->tty_inhibited) {
1077 if (ch == tp->tty_termios.c_cc[VSTART]
1078 || (tp->tty_termios.c_iflag & IXANY)) {
1079 tp->tty_inhibited = RUNNING;
1080 tp->tty_events = 1;
1081 if (ch == tp->tty_termios.c_cc[VSTART])
1082 continue;
1083 }
1084 }
1085 }
1086
1087 if (tp->tty_termios.c_lflag & ISIG) {
1088 /* Check for INTR (^?) and QUIT (^\) characters. */
1089 if (ch == tp->tty_termios.c_cc[VINTR]
1090 || ch == tp->tty_termios.c_cc[VQUIT]) {
1091 sig = SIGINT;
1092 if (ch == tp->tty_termios.c_cc[VQUIT]) sig = SIGQUIT;
1093 sigchar(tp, sig);
1094 (void) tty_echo(tp, ch);
1095 continue;
1096 }
1097 }
1098
1099 /* Is there space in the input buffer? */
1100 if (tp->tty_incount == buflen(tp->tty_inbuf)) {
1101 /* No space; discard in canonical mode, keep in raw mode. */
1102 if (tp->tty_termios.c_lflag & ICANON) continue;
1103 break;
1104 }
1105
1106 if (!(tp->tty_termios.c_lflag & ICANON)) {
1107 /* In raw mode all characters are "line breaks". */
1108 ch |= IN_EOT;
1109
1110 /* Start an inter-byte timer? */
1111 if (!timeset && tp->tty_termios.c_cc[VMIN] > 0
1112 && tp->tty_termios.c_cc[VTIME] > 0) {
1113 settimer(tp, TRUE);
1114 timeset = TRUE;
1115 }
1116 }
1117
1118 /* Perform the intricate function of echoing. */
1119 if (tp->tty_termios.c_lflag & (ECHO|ECHONL)) ch = tty_echo(tp, ch);
1120
1121 /* Save the character in the input queue. */
1122 *tp->tty_inhead++ = ch;
1123 if (tp->tty_inhead == bufend(tp->tty_inbuf))
1124 tp->tty_inhead = tp->tty_inbuf;
1125 tp->tty_incount++;
1126 if (ch & IN_EOT) tp->tty_eotct++;
1127
1128 /* Try to finish input if the queue threatens to overflow. */
1129 if (tp->tty_incount == buflen(tp->tty_inbuf)) in_transfer(tp);
1130 }
1131 return ct;
1132 }
1133
1134 /*===========================================================================*
1135 * echo *
1136 *===========================================================================*/
1137 PRIVATE int tty_echo(tp, ch)
1138 register tty_t *tp; /* terminal on which to echo */
1139 register int ch; /* pointer to character to echo */
1140 {
1141 /* Echo the character if echoing is on. Some control characters are echoed
1142 * with their normal effect, other control characters are echoed as "^X",
1143 * normal characters are echoed normally. EOF (^D) is echoed, but immediately
1144 * backspaced over. Return the character with the echoed length added to its
1145 * attributes.
1146 */
1147 int len, rp;
1148
1149 ch &= ~IN_LEN;
1150 if (!(tp->tty_termios.c_lflag & ECHO)) {
1151 if (ch == ('\n' | IN_EOT) && (tp->tty_termios.c_lflag
1152 & (ICANON|ECHONL)) == (ICANON|ECHONL))
1153 (*tp->tty_echo)(tp, '\n');
1154 return(ch);
1155 }
1156
1157 /* "Reprint" tells if the echo output has been messed up by other output. */
1158 rp = tp->tty_incount == 0 ? FALSE : tp->tty_reprint;
1159
1160 if ((ch & IN_CHAR) < ' ') {
1161 switch (ch & (IN_ESC|IN_EOF|IN_EOT|IN_CHAR)) {
1162 case '\t':
1163 len = 0;
1164 do {
1165 (*tp->tty_echo)(tp, ' ');
1166 len++;
1167 } while (len < TAB_SIZE && (tp->tty_position & TAB_MASK) != 0);
1168 break;
1169 case '\r' | IN_EOT:
1170 case '\n' | IN_EOT:
1171 (*tp->tty_echo)(tp, ch & IN_CHAR);
1172 len = 0;
1173 break;
1174 default:
1175 (*tp->tty_echo)(tp, '^');
1176 (*tp->tty_echo)(tp, '@' + (ch & IN_CHAR));
1177 len = 2;
1178 }
1179 } else
1180 if ((ch & IN_CHAR) == '\177') {
1181 /* A DEL prints as "^?". */
1182 (*tp->tty_echo)(tp, '^');
1183 (*tp->tty_echo)(tp, '?');
1184 len = 2;
1185 } else {
1186 (*tp->tty_echo)(tp, ch & IN_CHAR);
1187 len = 1;
1188 }
1189 if (ch & IN_EOF) while (len > 0) { (*tp->tty_echo)(tp, '\b'); len--; }
1190
1191 tp->tty_reprint = rp;
1192 return(ch | (len << IN_LSHIFT));
1193 }
1194
1195 /*===========================================================================*
1196 * rawecho *
1197 *===========================================================================*/
1198 PRIVATE void rawecho(tp, ch)
1199 register tty_t *tp;
1200 int ch;
1201 {
1202 /* Echo without interpretation if ECHO is set. */
1203 int rp = tp->tty_reprint;
1204 if (tp->tty_termios.c_lflag & ECHO) (*tp->tty_echo)(tp, ch);
1205 tp->tty_reprint = rp;
1206 }
1207
1208 /*===========================================================================*
1209 * back_over *
1210 *===========================================================================*/
1211 PRIVATE int back_over(tp)
1212 register tty_t *tp;
1213 {
1214 /* Backspace to previous character on screen and erase it. */
1215 u16_t *head;
1216 int len;
1217
1218 if (tp->tty_incount == 0) return(0); /* queue empty */
1219 head = tp->tty_inhead;
1220 if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
1221 if (*--head & IN_EOT) return(0); /* can't erase "line breaks" */
1222 if (tp->tty_reprint) reprint(tp); /* reprint if messed up */
1223 tp->tty_inhead = head;
1224 tp->tty_incount--;
1225 if (tp->tty_termios.c_lflag & ECHOE) {
1226 len = (*head & IN_LEN) >> IN_LSHIFT;
1227 while (len > 0) {
1228 rawecho(tp, '\b');
1229 rawecho(tp, ' ');
1230 rawecho(tp, '\b');
1231 len--;
1232 }
1233 }
1234 return(1); /* one character erased */
1235 }
1236
1237 /*===========================================================================*
1238 * reprint *
1239 *===========================================================================*/
1240 PRIVATE void reprint(tp)
1241 register tty_t *tp; /* pointer to tty struct */
1242 {
1243 /* Restore what has been echoed to screen before if the user input has been
1244 * messed up by output, or if REPRINT (^R) is typed.
1245 */
1246 int count;
1247 u16_t *head;
1248
1249 tp->tty_reprint = FALSE;
1250
1251 /* Find the last line break in the input. */
1252 head = tp->tty_inhead;
1253 count = tp->tty_incount;
1254 while (count > 0) {
1255 if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
1256 if (head[-1] & IN_EOT) break;
1257 head--;
1258 count--;
1259 }
1260 if (count == tp->tty_incount) return; /* no reason to reprint */
1261
1262 /* Show REPRINT (^R) and move to a new line. */
1263 (void) tty_echo(tp, tp->tty_termios.c_cc[VREPRINT] | IN_ESC);
1264 rawecho(tp, '\r');
1265 rawecho(tp, '\n');
1266
1267 /* Reprint from the last break onwards. */
1268 do {
1269 if (head == bufend(tp->tty_inbuf)) head = tp->tty_inbuf;
1270 *head = tty_echo(tp, *head);
1271 head++;
1272 count++;
1273 } while (count < tp->tty_incount);
1274 }
1275
1276 /*===========================================================================*
1277 * out_process *
1278 *===========================================================================*/
1279 PUBLIC void out_process(tp, bstart, bpos, bend, icount, ocount)
1280 tty_t *tp;
1281 char *bstart, *bpos, *bend; /* start/pos/end of circular buffer */
1282 int *icount; /* # input chars / input chars used */
1283 int *ocount; /* max output chars / output chars used */
1284 {
1285 /* Perform output processing on a circular buffer. *icount is the number of
1286 * bytes to process, and the number of bytes actually processed on return.
1287 * *ocount is the space available on input and the space used on output.
1288 * (Naturally *icount < *ocount.) The column position is updated modulo
1289 * the TAB size, because we really only need it for tabs.
1290 */
1291
1292 int tablen;
1293 int ict = *icount;
1294 int oct = *ocount;
1295 int pos = tp->tty_position;
1296
1297 while (ict > 0) {
1298 switch (*bpos) {
1299 case '\7':
1300 break;
1301 case '\b':
1302 pos--;
1303 break;
1304 case '\r':
1305 pos = 0;
1306 break;
1307 case '\n':
1308 if ((tp->tty_termios.c_oflag & (OPOST|ONLCR))
1309 == (OPOST|ONLCR)) {
1310 /* Map LF to CR+LF if there is space. Note that the
1311 * next character in the buffer is overwritten, so
1312 * we stop at this point.
1313 */
1314 if (oct >= 2) {
1315 *bpos = '\r';
1316 if (++bpos == bend) bpos = bstart;
1317 *bpos = '\n';
1318 pos = 0;
1319 ict--;
1320 oct -= 2;
1321 }
1322 goto out_done; /* no space or buffer got changed */
1323 }
1324 break;
1325 case '\t':
1326 /* Best guess for the tab length. */
1327 tablen = TAB_SIZE - (pos & TAB_MASK);
1328
1329 if ((tp->tty_termios.c_oflag & (OPOST|XTABS))
1330 == (OPOST|XTABS)) {
1331 /* Tabs must be expanded. */
1332 if (oct >= tablen) {
1333 pos += tablen;
1334 ict--;
1335 oct -= tablen;
1336 do {
1337 *bpos = ' ';
1338 if (++bpos == bend) bpos = bstart;
1339 } while (--tablen != 0);
1340 }
1341 goto out_done;
1342 }
1343 /* Tabs are output directly. */
1344 pos += tablen;
1345 break;
1346 default:
1347 /* Assume any other character prints as one character. */
1348 pos++;
1349 }
1350 if (++bpos == bend) bpos = bstart;
1351 ict--;
1352 oct--;
1353 }
1354 out_done:
1355 tp->tty_position = pos & TAB_MASK;
1356
1357 *icount -= ict; /* [io]ct are the number of chars not used */
1358 *ocount -= oct; /* *[io]count are the number of chars that are used */
1359 }
1360
1361 /*===========================================================================*
1362 * dev_ioctl *
1363 *===========================================================================*/
1364 PRIVATE void dev_ioctl(tp)
1365 tty_t *tp;
1366 {
1367 /* The ioctl's TCSETSW, TCSETSF and TCDRAIN wait for output to finish to make
1368 * sure that an attribute change doesn't affect the processing of current
1369 * output. Once output finishes the ioctl is executed as in do_ioctl().
1370 */
1371 int result;
1372
1373 if (tp->tty_outleft > 0) return; /* output not finished */
1374
1375 if (tp->tty_ioreq != TCDRAIN) {
1376 if (tp->tty_ioreq == TCSETSF) tty_icancel(tp);
1377 result = sys_vircopy(tp->tty_ioproc, D, tp->tty_iovir,
1378 SELF, D, (vir_bytes) &tp->tty_termios,
1379 (vir_bytes) sizeof(tp->tty_termios));
1380 setattr(tp);
1381 }
1382 tp->tty_ioreq = 0;
1383 tty_reply(REVIVE, tp->tty_iocaller, tp->tty_ioproc, result);
1384 }
1385
1386 /*===========================================================================*
1387 * setattr *
1388 *===========================================================================*/
1389 PRIVATE void setattr(tp)
1390 tty_t *tp;
1391 {
1392 /* Apply the new line attributes (raw/canonical, line speed, etc.) */
1393 u16_t *inp;
1394 int count;
1395
1396 if (!(tp->tty_termios.c_lflag & ICANON)) {
1397 /* Raw mode; put a "line break" on all characters in the input queue.
1398 * It is undefined what happens to the input queue when ICANON is
1399 * switched off, a process should use TCSAFLUSH to flush the queue.
1400 * Keeping the queue to preserve typeahead is the Right Thing, however
1401 * when a process does use TCSANOW to switch to raw mode.
1402 */
1403 count = tp->tty_eotct = tp->tty_incount;
1404 inp = tp->tty_intail;
1405 while (count > 0) {
1406 *inp |= IN_EOT;
1407 if (++inp == bufend(tp->tty_inbuf)) inp = tp->tty_inbuf;
1408 --count;
1409 }
1410 }
1411
1412 /* Inspect MIN and TIME. */
1413 settimer(tp, FALSE);
1414 if (tp->tty_termios.c_lflag & ICANON) {
1415 /* No MIN & TIME in canonical mode. */
1416 tp->tty_min = 1;
1417 } else {
1418 /* In raw mode MIN is the number of chars wanted, and TIME how long
1419 * to wait for them. With interesting exceptions if either is zero.
1420 */
1421 tp->tty_min = tp->tty_termios.c_cc[VMIN];
1422 if (tp->tty_min == 0 && tp->tty_termios.c_cc[VTIME] > 0)
1423 tp->tty_min = 1;
1424 }
1425
1426 if (!(tp->tty_termios.c_iflag & IXON)) {
1427 /* No start/stop output control, so don't leave output inhibited. */
1428 tp->tty_inhibited = RUNNING;
1429 tp->tty_events = 1;
1430 }
1431
1432 /* Setting the output speed to zero hangs up the phone. */
1433 if (tp->tty_termios.c_ospeed == B0) sigchar(tp, SIGHUP);
1434
1435 /* Set new line speed, character size, etc at the device level. */
1436 (*tp->tty_ioctl)(tp, 0);
1437 }
1438
1439 /*===========================================================================*
1440 * tty_reply *
1441 *===========================================================================*/
1442 PUBLIC void tty_reply(code, replyee, proc_nr, status)
1443 int code; /* TASK_REPLY or REVIVE */
1444 int replyee; /* destination address for the reply */
1445 int proc_nr; /* to whom should the reply go? */
1446 int status; /* reply code */
1447 {
1448 /* Send a reply to a process that wanted to read or write data. */
1449 message tty_mess;
1450
1451 tty_mess.m_type = code;
1452 tty_mess.REP_PROC_NR = proc_nr;
1453 tty_mess.REP_STATUS = status;
1454
1455 if ((status = send(replyee, &tty_mess)) != OK) {
1456 panic("TTY","tty_reply failed, status\n", status);
1457 }
1458 }
1459
1460 /*===========================================================================*
1461 * sigchar *
1462 *===========================================================================*/
1463 PUBLIC void sigchar(tp, sig)
1464 register tty_t *tp;
1465 int sig; /* SIGINT, SIGQUIT, SIGKILL or SIGHUP */
1466 {
1467 /* Process a SIGINT, SIGQUIT or SIGKILL char from the keyboard or SIGHUP from
1468 * a tty close, "stty 0", or a real RS-232 hangup. MM will send the signal to
1469 * the process group (INT, QUIT), all processes (KILL), or the session leader
1470 * (HUP).
1471 */
1472 int status;
1473
1474 if (tp->tty_pgrp != 0)
1475 if (OK != (status = sys_kill(tp->tty_pgrp, sig)))
1476 panic("TTY","Error, call to sys_kill failed", status);
1477
1478 if (!(tp->tty_termios.c_lflag & NOFLSH)) {
1479 tp->tty_incount = tp->tty_eotct = 0; /* kill earlier input */
1480 tp->tty_intail = tp->tty_inhead;
1481 (*tp->tty_ocancel)(tp, 0); /* kill all output */
1482 tp->tty_inhibited = RUNNING;
1483 tp->tty_events = 1;
1484 }
1485 }
1486
1487 /*===========================================================================*
1488 * tty_icancel *
1489 *===========================================================================*/
1490 PRIVATE void tty_icancel(tp)
1491 register tty_t *tp;
1492 {
1493 /* Discard all pending input, tty buffer or device. */
1494
1495 tp->tty_incount = tp->tty_eotct = 0;
1496 tp->tty_intail = tp->tty_inhead;
1497 (*tp->tty_icancel)(tp, 0);
1498 }
1499
1500 /*===========================================================================*
1501 * tty_init *
1502 *===========================================================================*/
1503 PRIVATE void tty_init()
1504 {
1505 /* Initialize tty structure and call device initialization routines. */
1506
1507 register tty_t *tp;
1508 int s;
1509 struct sigaction sa;
1510
1511 /* Initialize the terminal lines. */
1512 for (tp = FIRST_TTY,s=0; tp < END_TTY; tp++,s++) {
1513
1514 tp->tty_index = s;
1515
1516 tmr_inittimer(&tp->tty_tmr);
1517
1518 tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
1519 tp->tty_min = 1;
1520 tp->tty_termios = termios_defaults;
1521 tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
1522 tty_devnop;
1523 if (tp < tty_addr(NR_CONS)) {
1524 scr_init(tp);
1525 tp->tty_minor = CONS_MINOR + s;
1526 } else
1527 if (tp < tty_addr(NR_CONS+NR_RS_LINES)) {
1528 rs_init(tp);
1529 tp->tty_minor = RS232_MINOR + s-NR_CONS;
1530 } else {
1531 pty_init(tp);
1532 tp->tty_minor = s - (NR_CONS+NR_RS_LINES) + TTYPX_MINOR;
1533 }
1534 }
1535
1536 #if DEAD_CODE
1537 /* Install signal handlers. Ask PM to transform signal into message. */
1538 sa.sa_handler = SIG_MESS;
1539 sigemptyset(&sa.sa_mask);
1540 sa.sa_flags = 0;
1541 if (sigaction(SIGTERM,&sa,NULL)<0) panic("TTY","sigaction failed", errno);
1542 if (sigaction(SIGKMESS,&sa,NULL)<0) panic("TTY","sigaction failed", errno);
1543 if (sigaction(SIGKSTOP,&sa,NULL)<0) panic("TTY","sigaction failed", errno);
1544 #endif
1545 }
1546
1547 /*===========================================================================*
1548 * tty_timed_out *
1549 *===========================================================================*/
1550 PRIVATE void tty_timed_out(timer_t *tp)
1551 {
1552 /* This timer has expired. Set the events flag, to force processing. */
1553 tty_t *tty_ptr;
1554 tty_ptr = &tty_table[tmr_arg(tp)->ta_int];
1555 tty_ptr->tty_min = 0; /* force read to succeed */
1556 tty_ptr->tty_events = 1;
1557 }
1558
1559 /*===========================================================================*
1560 * expire_timers *
1561 *===========================================================================*/
1562 PRIVATE void expire_timers(void)
1563 {
1564 /* A synchronous alarm message was received. Check if there are any expired
1565 * timers. Possibly set the event flag and reschedule another alarm.
1566 */
1567 clock_t now; /* current time */
1568 int s;
1569
1570 /* Get the current time to compare the timers against. */
1571 if ((s=getuptime(&now)) != OK)
1572 panic("TTY","Couldn't get uptime from clock.", s);
1573
1574 /* Scan the queue of timers for expired timers. This dispatch the watchdog
1575 * functions of expired timers. Possibly a new alarm call must be scheduled.
1576 */
1577 tmrs_exptimers(&tty_timers, now, NULL);
1578 if (tty_timers == NULL) tty_next_timeout = TMR_NEVER;
1579 else { /* set new sync alarm */
1580 tty_next_timeout = tty_timers->tmr_exp_time;
1581 if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
1582 panic("TTY","Couldn't set synchronous alarm.", s);
1583 }
1584 }
1585
1586 /*===========================================================================*
1587 * settimer *
1588 *===========================================================================*/
1589 PRIVATE void settimer(tty_ptr, enable)
1590 tty_t *tty_ptr; /* line to set or unset a timer on */
1591 int enable; /* set timer if true, otherwise unset */
1592 {
1593 clock_t now; /* current time */
1594 clock_t exp_time;
1595 int s;
1596
1597 /* Get the current time to calculate the timeout time. */
1598 if ((s=getuptime(&now)) != OK)
1599 panic("TTY","Couldn't get uptime from clock.", s);
1600 if (enable) {
1601 exp_time = now + tty_ptr->tty_termios.c_cc[VTIME] * (HZ/10);
1602 /* Set a new timer for enabling the TTY events flags. */
1603 tmrs_settimer(&tty_timers, &tty_ptr->tty_tmr,
1604 exp_time, tty_timed_out, NULL);
1605 } else {
1606 /* Remove the timer from the active and expired lists. */
1607 tmrs_clrtimer(&tty_timers, &tty_ptr->tty_tmr, NULL);
1608 }
1609
1610 /* Now check if a new alarm must be scheduled. This happens when the front
1611 * of the timers queue was disabled or reinserted at another position, or
1612 * when a new timer was added to the front.
1613 */
1614 if (tty_timers == NULL) tty_next_timeout = TMR_NEVER;
1615 else if (tty_timers->tmr_exp_time != tty_next_timeout) {
1616 tty_next_timeout = tty_timers->tmr_exp_time;
1617 if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
1618 panic("TTY","Couldn't set synchronous alarm.", s);
1619 }
1620 }
1621
1622 /*===========================================================================*
1623 * tty_devnop *
1624 *===========================================================================*/
1625 PUBLIC int tty_devnop(tp, try)
1626 tty_t *tp;
1627 int try;
1628 {
1629 /* Some functions need not be implemented at the device level. */
1630 }
1631
1632 /*===========================================================================*
1633 * do_select *
1634 *===========================================================================*/
1635 PRIVATE void do_select(tp, m_ptr)
1636 register tty_t *tp; /* pointer to tty struct */
1637 register message *m_ptr; /* pointer to message sent to the task */
1638 {
1639 int ops, ready_ops = 0, watch;
1640
1641 ops = m_ptr->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR);
1642 watch = (m_ptr->PROC_NR & SEL_NOTIFY) ? 1 : 0;
1643
1644 ready_ops = select_try(tp, ops);
1645
1646 if (!ready_ops && ops && watch) {
1647 tp->tty_select_ops |= ops;
1648 tp->tty_select_proc = m_ptr->m_source;
1649 }
1650
1651 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, ready_ops);
1652
1653 return;
1654 }
1655
1656 #if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
1657 /*===========================================================================*
1658 * compat_getp *
1659 *===========================================================================*/
1660 PRIVATE int compat_getp(tp, sg)
1661 tty_t *tp;
1662 struct sgttyb *sg;
1663 {
1664 /* Translate an old TIOCGETP to the termios equivalent. */
1665 int flgs;
1666
1667 sg->sg_erase = tp->tty_termios.c_cc[VERASE];
1668 sg->sg_kill = tp->tty_termios.c_cc[VKILL];
1669 sg->sg_ospeed = tspd2sgspd(cfgetospeed(&tp->tty_termios));
1670 sg->sg_ispeed = tspd2sgspd(cfgetispeed(&tp->tty_termios));
1671
1672 flgs = 0;
1673
1674 /* XTABS - if OPOST and XTABS */
1675 if ((tp->tty_termios.c_oflag & (OPOST|XTABS)) == (OPOST|XTABS))
1676 flgs |= 0006000;
1677
1678 /* BITS5..BITS8 - map directly to CS5..CS8 */
1679 flgs |= (tp->tty_termios.c_cflag & CSIZE) << (8-2);
1680
1681 /* EVENP - if PARENB and not PARODD */
1682 if ((tp->tty_termios.c_cflag & (PARENB|PARODD)) == PARENB)
1683 flgs |= 0000200;
1684
1685 /* ODDP - if PARENB and PARODD */
1686 if ((tp->tty_termios.c_cflag & (PARENB|PARODD)) == (PARENB|PARODD))
1687 flgs |= 0000100;
1688
1689 /* RAW - if not ICANON and not ISIG */
1690 if (!(tp->tty_termios.c_lflag & (ICANON|ISIG)))
1691 flgs |= 0000040;
1692
1693 /* CRMOD - if ICRNL */
1694 if (tp->tty_termios.c_iflag & ICRNL)
1695 flgs |= 0000020;
1696
1697 /* ECHO - if ECHO */
1698 if (tp->tty_termios.c_lflag & ECHO)
1699 flgs |= 0000010;
1700
1701 /* CBREAK - if not ICANON and ISIG */
1702 if ((tp->tty_termios.c_lflag & (ICANON|ISIG)) == ISIG)
1703 flgs |= 0000002;
1704
1705 sg->sg_flags = flgs;
1706 return(OK);
1707 }
1708
1709 /*===========================================================================*
1710 * compat_getc *
1711 *===========================================================================*/
1712 PRIVATE int compat_getc(tp, tc)
1713 tty_t *tp;
1714 struct tchars *tc;
1715 {
1716 /* Translate an old TIOCGETC to the termios equivalent. */
1717
1718 tc->t_intrc = tp->tty_termios.c_cc[VINTR];
1719 tc->t_quitc = tp->tty_termios.c_cc[VQUIT];
1720 tc->t_startc = tp->tty_termios.c_cc[VSTART];
1721 tc->t_stopc = tp->tty_termios.c_cc[VSTOP];
1722 tc->t_brkc = tp->tty_termios.c_cc[VEOL];
1723 tc->t_eofc = tp->tty_termios.c_cc[VEOF];
1724 return(OK);
1725 }
1726
1727 /*===========================================================================*
1728 * compat_setp *
1729 *===========================================================================*/
1730 PRIVATE int compat_setp(tp, sg)
1731 tty_t *tp;
1732 struct sgttyb *sg;
1733 {
1734 /* Translate an old TIOCSETP to the termios equivalent. */
1735 struct termios termios;
1736 int flags;
1737
1738 termios = tp->tty_termios;
1739
1740 termios.c_cc[VERASE] = sg->sg_erase;
1741 termios.c_cc[VKILL] = sg->sg_kill;
1742 cfsetispeed(&termios, sgspd2tspd(sg->sg_ispeed & BYTE));
1743 cfsetospeed(&termios, sgspd2tspd(sg->sg_ospeed & BYTE));
1744 flags = sg->sg_flags;
1745
1746 /* Input flags */
1747
1748 /* BRKINT - not changed */
1749 /* ICRNL - set if CRMOD is set and not RAW */
1750 /* (CRMOD also controls output) */
1751 termios.c_iflag &= ~ICRNL;
1752 if ((flags & 0000020) && !(flags & 0000040))
1753 termios.c_iflag |= ICRNL;
1754
1755 /* IGNBRK - not changed */
1756 /* IGNCR - forced off (ignoring cr's is not supported) */
1757 termios.c_iflag &= ~IGNCR;
1758
1759 /* IGNPAR - not changed */
1760 /* INLCR - forced off (mapping nl's to cr's is not supported) */
1761 termios.c_iflag &= ~INLCR;
1762
1763 /* INPCK - not changed */
1764 /* ISTRIP - not changed */
1765 /* IXOFF - not changed */
1766 /* IXON - forced on if not RAW */
1767 termios.c_iflag &= ~IXON;
1768 if (!(flags & 0000040))
1769 termios.c_iflag |= IXON;
1770
1771 /* PARMRK - not changed */
1772
1773 /* Output flags */
1774
1775 /* OPOST - forced on if not RAW */
1776 termios.c_oflag &= ~OPOST;
1777 if (!(flags & 0000040))
1778 termios.c_oflag |= OPOST;
1779
1780 /* ONLCR - forced on if CRMOD */
1781 termios.c_oflag &= ~ONLCR;
1782 if (flags & 0000020)
1783 termios.c_oflag |= ONLCR;
1784
1785 /* XTABS - forced on if XTABS */
1786 termios.c_oflag &= ~XTABS;
1787 if (flags & 0006000)
1788 termios.c_oflag |= XTABS;
1789
1790 /* CLOCAL - not changed */
1791 /* CREAD - forced on (receiver is always enabled) */
1792 termios.c_cflag |= CREAD;
1793
1794 /* CSIZE - CS5-CS8 correspond directly to BITS5-BITS8 */
1795 termios.c_cflag = (termios.c_cflag & ~CSIZE) | ((flags & 0001400) >> (8-2));
1796
1797 /* CSTOPB - not changed */
1798 /* HUPCL - not changed */
1799 /* PARENB - set if EVENP or ODDP is set */
1800 termios.c_cflag &= ~PARENB;
1801 if (flags & (0000200|0000100))
1802 termios.c_cflag |= PARENB;
1803
1804 /* PARODD - set if ODDP is set */
1805 termios.c_cflag &= ~PARODD;
1806 if (flags & 0000100)
1807 termios.c_cflag |= PARODD;
1808
1809 /* Local flags */
1810
1811 /* ECHO - set if ECHO is set */
1812 termios.c_lflag &= ~ECHO;
1813 if (flags & 0000010)
1814 termios.c_lflag |= ECHO;
1815
1816 /* ECHOE - not changed */
1817 /* ECHOK - not changed */
1818 /* ECHONL - not changed */
1819 /* ICANON - set if neither CBREAK nor RAW */
1820 termios.c_lflag &= ~ICANON;
1821 if (!(flags & (0000002|0000040)))
1822 termios.c_lflag |= ICANON;
1823
1824 /* IEXTEN - set if not RAW */
1825 /* ISIG - set if not RAW */
1826 termios.c_lflag &= ~(IEXTEN|ISIG);
1827 if (!(flags & 0000040))
1828 termios.c_lflag |= (IEXTEN|ISIG);
1829
1830 /* NOFLSH - not changed */
1831 /* TOSTOP - not changed */
1832
1833 tp->tty_termios = termios;
1834 setattr(tp);
1835 return(OK);
1836 }
1837
1838 /*===========================================================================*
1839 * compat_setc *
1840 *===========================================================================*/
1841 PRIVATE int compat_setc(tp, tc)
1842 tty_t *tp;
1843 struct tchars *tc;
1844 {
1845 /* Translate an old TIOCSETC to the termios equivalent. */
1846 struct termios termios;
1847
1848 termios = tp->tty_termios;
1849
1850 termios.c_cc[VINTR] = tc->t_intrc;
1851 termios.c_cc[VQUIT] = tc->t_quitc;
1852 termios.c_cc[VSTART] = tc->t_startc;
1853 termios.c_cc[VSTOP] = tc->t_stopc;
1854 termios.c_cc[VEOL] = tc->t_brkc;
1855 termios.c_cc[VEOF] = tc->t_eofc;
1856
1857 tp->tty_termios = termios;
1858 setattr(tp);
1859 return(OK);
1860 }
1861
1862 /* Table of termios line speed to sgtty line speed translations. All termios
1863 * speeds are present even if sgtty didn't know about them. (Now it does.)
1864 */
1865 PRIVATE struct s2s {
1866 speed_t tspd;
1867 u8_t sgspd;
1868 } ts2sgs[] = {
1869 { B0, 0 },
1870 { B50, 50 },
1871 { B75, 75 },
1872 { B110, 1 },
1873 { B134, 134 },
1874 { B200, 2 },
1875 { B300, 3 },
1876 { B600, 6 },
1877 { B1200, 12 },
1878 { B1800, 18 },
1879 { B2400, 24 },
1880 { B4800, 48 },
1881 { B9600, 96 },
1882 { B19200, 192 },
1883 { B38400, 195 },
1884 { B57600, 194 },
1885 { B115200, 193 },
1886 };
1887
1888 /*===========================================================================*
1889 * tspd2sgspd *
1890 *===========================================================================*/
1891 PRIVATE int tspd2sgspd(tspd)
1892 speed_t tspd;
1893 {
1894 /* Translate a termios speed to sgtty speed. */
1895 struct s2s *s;
1896
1897 for (s = ts2sgs; s < ts2sgs + sizeof(ts2sgs)/sizeof(ts2sgs[0]); s++) {
1898 if (s->tspd == tspd) return(s->sgspd);
1899 }
1900 return 96;
1901 }
1902
1903 /*===========================================================================*
1904 * sgspd2tspd *
1905 *===========================================================================*/
1906 PRIVATE speed_t sgspd2tspd(sgspd)
1907 int sgspd;
1908 {
1909 /* Translate a sgtty speed to termios speed. */
1910 struct s2s *s;
1911
1912 for (s = ts2sgs; s < ts2sgs + sizeof(ts2sgs)/sizeof(ts2sgs[0]); s++) {
1913 if (s->sgspd == sgspd) return(s->tspd);
1914 }
1915 return B9600;
1916 }
1917
1918 #if ENABLE_BINCOMPAT
1919 /*===========================================================================*
1920 * do_ioctl_compat *
1921 *===========================================================================*/
1922 PRIVATE void do_ioctl_compat(tp, m_ptr)
1923 tty_t *tp;
1924 message *m_ptr;
1925 {
1926 /* Handle the old sgtty ioctl's that packed the sgtty or tchars struct into
1927 * the Minix message. Efficient then, troublesome now.
1928 */
1929 int minor, proc, func, result, r;
1930 long flags, erki, spek;
1931 u8_t erase, kill, intr, quit, xon, xoff, brk, eof, ispeed, ospeed;
1932 struct sgttyb sg;
1933 struct tchars tc;
1934 message reply_mess;
1935
1936 minor = m_ptr->TTY_LINE;
1937 proc = m_ptr->PROC_NR;
1938 func = m_ptr->REQUEST;
1939 spek = m_ptr->m2_l1;
1940 flags = m_ptr->m2_l2;
1941
1942 switch(func)
1943 {
1944 case (('t'<<8) | 8): /* TIOCGETP */
1945 r = compat_getp(tp, &sg);
1946 erase = sg.sg_erase;
1947 kill = sg.sg_kill;
1948 ispeed = sg.sg_ispeed;
1949 ospeed = sg.sg_ospeed;
1950 flags = sg.sg_flags;
1951 erki = ((long)ospeed<<24) | ((long)ispeed<<16) | ((long)erase<<8) |kill;
1952 break;
1953 case (('t'<<8) | 18): /* TIOCGETC */
1954 r = compat_getc(tp, &tc);
1955 intr = tc.t_intrc;
1956 quit = tc.t_quitc;
1957 xon = tc.t_startc;
1958 xoff = tc.t_stopc;
1959 brk = tc.t_brkc;
1960 eof = tc.t_eofc;
1961 erki = ((long)intr<<24) | ((long)quit<<16) | ((long)xon<<8) | xoff;
1962 flags = (eof << 8) | brk;
1963 break;
1964 case (('t'<<8) | 17): /* TIOCSETC */
1965 tc.t_stopc = (spek >> 0) & 0xFF;
1966 tc.t_startc = (spek >> 8) & 0xFF;
1967 tc.t_quitc = (spek >> 16) & 0xFF;
1968 tc.t_intrc = (spek >> 24) & 0xFF;
1969 tc.t_brkc = (flags >> 0) & 0xFF;
1970 tc.t_eofc = (flags >> 8) & 0xFF;
1971 r = compat_setc(tp, &tc);
1972 break;
1973 case (('t'<<8) | 9): /* TIOCSETP */
1974 sg.sg_erase = (spek >> 8) & 0xFF;
1975 sg.sg_kill = (spek >> 0) & 0xFF;
1976 sg.sg_ispeed = (spek >> 16) & 0xFF;
1977 sg.sg_ospeed = (spek >> 24) & 0xFF;
1978 sg.sg_flags = flags;
1979 r = compat_setp(tp, &sg);
1980 break;
1981 default:
1982 r = ENOTTY;
1983 }
1984 reply_mess.m_type = TASK_REPLY;
1985 reply_mess.REP_PROC_NR = m_ptr->PROC_NR;
1986 reply_mess.REP_STATUS = r;
1987 reply_mess.m2_l1 = erki;
1988 reply_mess.m2_l2 = flags;
1989 send(m_ptr->m_source, &reply_mess);
1990 }
1991 #endif /* ENABLE_BINCOMPAT */
1992 #endif /* ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT */
1993
Cache object: 94afbe9940f83a7dbbc1031bc2252cbc
|