The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/drivers/tty/tty.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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) &param.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) &param.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, &param.sg);
  658         r = sys_vircopy(SELF, D, (vir_bytes) &param.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) &param.sg, (vir_bytes) size);
  666         if (r != OK) break;
  667         compat_setp(tp, &param.sg);
  668         break;
  669 
  670     case TIOCGETC:
  671         compat_getc(tp, &param.tc);
  672         r = sys_vircopy(SELF, D, (vir_bytes) &param.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) &param.tc, (vir_bytes) size);
  680         if (r != OK) break;
  681         compat_setc(tp, &param.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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.