tty.c

Go to the documentation of this file.
00001 /* This file contains the terminal driver, both for the IBM console and regular
00002  * ASCII terminals.  It handles only the device-independent part of a TTY, the
00003  * device dependent parts are in console.c, rs232.c, etc.  This file contains
00004  * two main entry points, tty_task() and tty_wakeup(), and several minor entry
00005  * points for use by the device-dependent code.
00006  *
00007  * The device-independent part accepts "keyboard" input from the device-
00008  * dependent part, performs input processing (special key interpretation),
00009  * and sends the input to a process reading from the TTY.  Output to a TTY
00010  * is sent to the device-dependent code for output processing and "screen"
00011  * display.  Input processing is done by the device by calling 'in_process'
00012  * on the input characters, output processing may be done by the device itself
00013  * or by calling 'out_process'.  The TTY takes care of input queuing, the
00014  * device does the output queuing.  If a device receives an external signal,
00015  * like an interrupt, then it causes tty_wakeup() to be run by the CLOCK task
00016  * to, you guessed it, wake up the TTY to check if input or output can
00017  * continue.
00018  *
00019  * The valid messages and their parameters are:
00020  *
00021  *   HARD_INT:       output has been completed or input has arrived
00022  *   SYS_SIG:      e.g., MINIX wants to shutdown; run code to cleanly stop
00023  *   DEV_READ:       a process wants to read from a terminal
00024  *   DEV_WRITE:      a process wants to write on a terminal
00025  *   DEV_IOCTL:      a process wants to change a terminal's parameters
00026  *   DEV_OPEN:       a tty line has been opened
00027  *   DEV_CLOSE:      a tty line has been closed
00028  *   DEV_SELECT:     start select notification request
00029  *   DEV_STATUS:     FS wants to know status for SELECT or REVIVE
00030  *   CANCEL:         terminate a previous incomplete system call immediately
00031  *
00032  *    m_type      TTY_LINE   IO_ENDPT    COUNT   TTY_SPEK  TTY_FLAGS  ADDRESS
00033  * ---------------------------------------------------------------------------
00034  * | HARD_INT    |         |         |         |         |         |         |
00035  * |-------------+---------+---------+---------+---------+---------+---------|
00036  * | SYS_SIG     | sig set |         |         |         |         |         |
00037  * |-------------+---------+---------+---------+---------+---------+---------|
00038  * | DEV_READ    |minor dev| proc nr |  count  |         O_NONBLOCK| buf ptr |
00039  * |-------------+---------+---------+---------+---------+---------+---------|
00040  * | DEV_WRITE   |minor dev| proc nr |  count  |         |         | buf ptr |
00041  * |-------------+---------+---------+---------+---------+---------+---------|
00042  * | DEV_IOCTL   |minor dev| proc nr |func code|erase etc|  flags  |         |
00043  * |-------------+---------+---------+---------+---------+---------+---------|
00044  * | DEV_OPEN    |minor dev| proc nr | O_NOCTTY|         |         |         |
00045  * |-------------+---------+---------+---------+---------+---------+---------|
00046  * | DEV_CLOSE   |minor dev| proc nr |         |         |         |         |
00047  * |-------------+---------+---------+---------+---------+---------+---------|
00048  * | DEV_STATUS  |         |         |         |         |         |         |
00049  * |-------------+---------+---------+---------+---------+---------+---------|
00050  * | CANCEL      |minor dev| proc nr |         |         |         |         |
00051  * ---------------------------------------------------------------------------
00052  *
00053  * Changes:
00054  *   Jan 20, 2004   moved TTY driver to user-space  (Jorrit N. Herder)
00055  *   Sep 20, 2004   local timer management/ sync alarms  (Jorrit N. Herder)
00056  *   Jul 13, 2004   support for function key observers  (Jorrit N. Herder)  
00057  */
00058 
00059 #include "../drivers.h"
00060 #include "../drivers.h"
00061 #include <termios.h>
00062 #if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
00063 #include <sgtty.h>
00064 #endif
00065 #include <sys/ioc_tty.h>
00066 #include <signal.h>
00067 #include <minix/callnr.h>
00068 #if (CHIP == INTEL)
00069 #include <minix/keymap.h>
00070 #endif
00071 #include "tty.h"
00072 
00073 #include <sys/time.h>
00074 #include <sys/select.h>
00075 
00076 extern int irq_hook_id;
00077 
00078 unsigned long kbd_irq_set = 0;
00079 unsigned long rs_irq_set = 0;
00080 
00081 /* Address of a tty structure. */
00082 #define tty_addr(line)  (&tty_table[line])
00083 
00084 /* Macros for magic tty types. */
00085 #define isconsole(tp)   ((tp) < tty_addr(NR_CONS))
00086 #define ispty(tp)       ((tp) >= tty_addr(NR_CONS+NR_RS_LINES))
00087 
00088 /* Macros for magic tty structure pointers. */
00089 #define FIRST_TTY       tty_addr(0)
00090 #define END_TTY         tty_addr(sizeof(tty_table) / sizeof(tty_table[0]))
00091 
00092 /* A device exists if at least its 'devread' function is defined. */
00093 #define tty_active(tp)  ((tp)->tty_devread != NULL)
00094 
00095 /* RS232 lines or pseudo terminals can be completely configured out. */
00096 #if NR_RS_LINES == 0
00097 #define rs_init(tp)     ((void) 0)
00098 #endif
00099 #if NR_PTYS == 0
00100 #define pty_init(tp)    ((void) 0)
00101 #define do_pty(tp, mp)  ((void) 0)
00102 #endif
00103 
00104 struct kmessages kmess;
00105 
00106 FORWARD _PROTOTYPE( void tty_timed_out, (timer_t *tp)                   );
00107 FORWARD _PROTOTYPE( void expire_timers, (void)                          );
00108 FORWARD _PROTOTYPE( void settimer, (tty_t *tty_ptr, int enable)         );
00109 FORWARD _PROTOTYPE( void do_cancel, (tty_t *tp, message *m_ptr)         );
00110 FORWARD _PROTOTYPE( void do_ioctl, (tty_t *tp, message *m_ptr)          );
00111 FORWARD _PROTOTYPE( void do_open, (tty_t *tp, message *m_ptr)           );
00112 FORWARD _PROTOTYPE( void do_close, (tty_t *tp, message *m_ptr)          );
00113 FORWARD _PROTOTYPE( void do_read, (tty_t *tp, message *m_ptr)           );
00114 FORWARD _PROTOTYPE( void do_write, (tty_t *tp, message *m_ptr)          );
00115 FORWARD _PROTOTYPE( void do_select, (tty_t *tp, message *m_ptr)         );
00116 FORWARD _PROTOTYPE( void do_status, (message *m_ptr)                    );
00117 FORWARD _PROTOTYPE( void in_transfer, (tty_t *tp)                       );
00118 FORWARD _PROTOTYPE( int tty_echo, (tty_t *tp, int ch)                   );
00119 FORWARD _PROTOTYPE( void rawecho, (tty_t *tp, int ch)                   );
00120 FORWARD _PROTOTYPE( int back_over, (tty_t *tp)                          );
00121 FORWARD _PROTOTYPE( void reprint, (tty_t *tp)                           );
00122 FORWARD _PROTOTYPE( void dev_ioctl, (tty_t *tp)                         );
00123 FORWARD _PROTOTYPE( void setattr, (tty_t *tp)                           );
00124 FORWARD _PROTOTYPE( void tty_icancel, (tty_t *tp)                       );
00125 FORWARD _PROTOTYPE( void tty_init, (void)                               );
00126 #if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
00127 FORWARD _PROTOTYPE( int compat_getp, (tty_t *tp, struct sgttyb *sg)     );
00128 FORWARD _PROTOTYPE( int compat_getc, (tty_t *tp, struct tchars *sg)     );
00129 FORWARD _PROTOTYPE( int compat_setp, (tty_t *tp, struct sgttyb *sg)     );
00130 FORWARD _PROTOTYPE( int compat_setc, (tty_t *tp, struct tchars *sg)     );
00131 FORWARD _PROTOTYPE( int tspd2sgspd, (speed_t tspd)                      );
00132 FORWARD _PROTOTYPE( speed_t sgspd2tspd, (int sgspd)                     );
00133 #if ENABLE_BINCOMPAT
00134 FORWARD _PROTOTYPE( void do_ioctl_compat, (tty_t *tp, message *m_ptr)   );
00135 #endif
00136 #endif
00137 
00138 /* Default attributes. */
00139 PRIVATE struct termios termios_defaults = {
00140   TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF, TSPEED_DEF, TSPEED_DEF,
00141   {
00142         TEOF_DEF, TEOL_DEF, TERASE_DEF, TINTR_DEF, TKILL_DEF, TMIN_DEF,
00143         TQUIT_DEF, TTIME_DEF, TSUSP_DEF, TSTART_DEF, TSTOP_DEF,
00144         TREPRINT_DEF, TLNEXT_DEF, TDISCARD_DEF,
00145   },
00146 };
00147 PRIVATE struct winsize winsize_defaults;        /* = all zeroes */
00148 
00149 /* Global variables for the TTY task (declared extern in tty.h). */
00150 PUBLIC tty_t tty_table[NR_CONS+NR_RS_LINES+NR_PTYS];
00151 PUBLIC int ccurrent;                    /* currently active console */
00152 PUBLIC timer_t *tty_timers;             /* queue of TTY timers */
00153 PUBLIC clock_t tty_next_timeout;        /* time that the next alarm is due */
00154 PUBLIC struct machine machine;          /* kernel environment variables */
00155 
00156 /*===========================================================================*
00157  *                              tty_task                                     *
00158  *===========================================================================*/
00159 PUBLIC void main(void)
00160 {
00161 /* Main routine of the terminal task. */
00162 
00163   message tty_mess;             /* buffer for all incoming messages */
00164   unsigned line;
00165   int r, s;
00166   register struct proc *rp;
00167   register tty_t *tp;
00168 
00169 #if DEBUG
00170   kputc('H');
00171   kputc('e');
00172   kputc('l');
00173   kputc('l');
00174   kputc('o');
00175   kputc(',');
00176   kputc(' ');
00177   printf("TTY\n");
00178 #endif
00179 
00180   /* Get kernel environment (protected_mode, pc_at and ega are needed). */ 
00181   if (OK != (s=sys_getmachine(&machine))) {
00182     panic("TTY","Couldn't obtain kernel environment.", s);
00183   }
00184 
00185   /* Initialize the TTY driver. */
00186   tty_init();
00187 
00188   /* Final one-time keyboard initialization. */
00189   kb_init_once();
00190 
00191   printf("\n");
00192 
00193   while (TRUE) {
00194 
00195         /* Check for and handle any events on any of the ttys. */
00196         for (tp = FIRST_TTY; tp < END_TTY; tp++) {
00197                 if (tp->tty_events) handle_events(tp);
00198         }
00199 
00200         /* Get a request message. */
00201         r= receive(ANY, &tty_mess);
00202         if (r != 0)
00203                 panic("TTY", "receive failed with %d", r);
00204 
00205         /* First handle all kernel notification types that the TTY supports. 
00206          *  - An alarm went off, expire all timers and handle the events. 
00207          *  - A hardware interrupt also is an invitation to check for events. 
00208          *  - A new kernel message is available for printing.
00209          *  - Reset the console on system shutdown. 
00210          * Then see if this message is different from a normal device driver
00211          * request and should be handled separately. These extra functions
00212          * do not operate on a device, in constrast to the driver requests. 
00213          */
00214         switch (tty_mess.m_type) { 
00215         case SYN_ALARM:                 /* fall through */
00216                 expire_timers();        /* run watchdogs of expired timers */
00217                 continue;               /* contine to check for events */
00218         case DEV_PING:
00219                 notify(tty_mess.m_source);
00220                 continue;
00221         case HARD_INT: {                /* hardware interrupt notification */
00222                 if (tty_mess.NOTIFY_ARG & kbd_irq_set)
00223                         kbd_interrupt(&tty_mess);/* fetch chars from keyboard */
00224 #if NR_RS_LINES > 0
00225                 if (tty_mess.NOTIFY_ARG & rs_irq_set)
00226                         rs_interrupt(&tty_mess);/* serial I/O */
00227 #endif
00228                 expire_timers();        /* run watchdogs of expired timers */
00229                 continue;               /* contine to check for events */
00230         }
00231         case PROC_EVENT: {
00232                 cons_stop();            /* switch to primary console */
00233                 printf("TTY got PROC_EVENT, assuming SIGTERM\n");
00234 #if DEAD_CODE
00235                 if (irq_hook_id != -1) {
00236                         sys_irqdisable(&irq_hook_id);
00237                         sys_irqrmpolicy(KEYBOARD_IRQ, &irq_hook_id);
00238                 }
00239 #endif
00240                 continue;
00241         }
00242         case SYS_SIG: {                 /* system signal */
00243                 sigset_t sigset = (sigset_t) tty_mess.NOTIFY_ARG;
00244                 if (sigismember(&sigset, SIGKMESS)) do_new_kmess(&tty_mess);
00245                 continue;
00246         }
00247         case DIAGNOSTICS:               /* a server wants to print some */
00248                 do_diagnostics(&tty_mess);
00249                 continue;
00250         case GET_KMESS:
00251                 do_get_kmess(&tty_mess);
00252                 continue;
00253         case FKEY_CONTROL:              /* (un)register a fkey observer */
00254                 do_fkey_ctl(&tty_mess);
00255                 continue;
00256         default:                        /* should be a driver request */
00257                 ;                       /* do nothing; end switch */
00258         }
00259 
00260         /* Only device requests should get to this point. All requests, 
00261          * except DEV_STATUS, have a minor device number. Check this
00262          * exception and get the minor device number otherwise.
00263          */
00264         if (tty_mess.m_type == DEV_STATUS) {
00265                 do_status(&tty_mess);
00266                 continue;
00267         }
00268         line = tty_mess.TTY_LINE;
00269         if (line == KBD_MINOR) {
00270                 do_kbd(&tty_mess);
00271                 continue;
00272         } else if (line == KBDAUX_MINOR) {
00273                 do_kbdaux(&tty_mess);
00274                 continue;
00275         } else if (line == VIDEO_MINOR) {
00276                 do_video(&tty_mess);
00277                 continue;
00278         } else if ((line - CONS_MINOR) < NR_CONS) {
00279                 tp = tty_addr(line - CONS_MINOR);
00280         } else if (line == LOG_MINOR) {
00281                 tp = tty_addr(0);
00282         } else if ((line - RS232_MINOR) < NR_RS_LINES) {
00283                 tp = tty_addr(line - RS232_MINOR + NR_CONS);
00284         } else if ((line - TTYPX_MINOR) < NR_PTYS) {
00285                 tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
00286         } else if ((line - PTYPX_MINOR) < NR_PTYS) {
00287                 tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
00288                 if (tty_mess.m_type != DEV_IOCTL) {
00289                         do_pty(tp, &tty_mess);
00290                         continue;
00291                 }
00292         } else {
00293                 tp = NULL;
00294         }
00295 
00296         /* If the device doesn't exist or is not configured return ENXIO. */
00297         if (tp == NULL || ! tty_active(tp)) {
00298                 printf("Warning, TTY got illegal request %d from %d\n",
00299                         tty_mess.m_type, tty_mess.m_source);
00300                 if (tty_mess.m_source != LOG_PROC_NR)
00301                 {
00302                         tty_reply(TASK_REPLY, tty_mess.m_source,
00303                                                 tty_mess.IO_ENDPT, ENXIO);
00304                 }
00305                 continue;
00306         }
00307 
00308         /* Execute the requested device driver function. */
00309         switch (tty_mess.m_type) {
00310             case DEV_READ:       do_read(tp, &tty_mess);          break;
00311             case DEV_WRITE:      do_write(tp, &tty_mess);         break;
00312             case DEV_IOCTL:      do_ioctl(tp, &tty_mess);         break;
00313             case DEV_OPEN:       do_open(tp, &tty_mess);          break;
00314             case DEV_CLOSE:      do_close(tp, &tty_mess);         break;
00315             case DEV_SELECT:     do_select(tp, &tty_mess);        break;
00316             case CANCEL:         do_cancel(tp, &tty_mess);        break;
00317             default:            
00318                 printf("Warning, TTY got unexpected request %d from %d\n",
00319                         tty_mess.m_type, tty_mess.m_source);
00320             tty_reply(TASK_REPLY, tty_mess.m_source,
00321                                                 tty_mess.IO_ENDPT, EINVAL);
00322         }
00323   }
00324 }
00325 
00326 /*===========================================================================*
00327  *                              do_status                                    *
00328  *===========================================================================*/
00329 PRIVATE void do_status(m_ptr)
00330 message *m_ptr;
00331 {
00332   register struct tty *tp;
00333   int event_found;
00334   int status;
00335   int ops;
00336   
00337   /* Check for select or revive events on any of the ttys. If we found an, 
00338    * event return a single status message for it. The FS will make another 
00339    * call to see if there is more.
00340    */
00341   event_found = 0;
00342   for (tp = FIRST_TTY; tp < END_TTY; tp++) {
00343         if ((ops = select_try(tp, tp->tty_select_ops)) && 
00344                         tp->tty_select_proc == m_ptr->m_source) {
00345 
00346                 /* I/O for a selected minor device is ready. */
00347                 m_ptr->m_type = DEV_IO_READY;
00348                 m_ptr->DEV_MINOR = tp->tty_minor;
00349                 m_ptr->DEV_SEL_OPS = ops;
00350 
00351                 tp->tty_select_ops &= ~ops;     /* unmark select event */
00352                 event_found = 1;
00353                 break;
00354         }
00355         else if (tp->tty_inrevived && tp->tty_incaller == m_ptr->m_source) {
00356                 
00357                 /* Suspended request finished. Send a REVIVE. */
00358                 m_ptr->m_type = DEV_REVIVE;
00359                 m_ptr->REP_ENDPT = tp->tty_inproc;
00360                 m_ptr->REP_STATUS = tp->tty_incum;
00361 
00362                 tp->tty_inleft = tp->tty_incum = 0;
00363                 tp->tty_inrevived = 0;          /* unmark revive event */
00364                 event_found = 1;
00365                 break;
00366         }
00367         else if (tp->tty_outrevived && tp->tty_outcaller == m_ptr->m_source) {
00368                 
00369                 /* Suspended request finished. Send a REVIVE. */
00370                 m_ptr->m_type = DEV_REVIVE;
00371                 m_ptr->REP_ENDPT = tp->tty_outproc;
00372                 m_ptr->REP_STATUS = tp->tty_outcum;
00373 
00374                 tp->tty_outcum = 0;
00375                 tp->tty_outrevived = 0;         /* unmark revive event */
00376                 event_found = 1;
00377                 break;
00378         }
00379   }
00380 
00381 #if NR_PTYS > 0
00382   if (!event_found)
00383         event_found = pty_status(m_ptr);
00384 #endif
00385   if (!event_found)
00386         event_found= kbd_status(m_ptr);
00387 
00388   if (! event_found) {
00389         /* No events of interest were found. Return an empty message. */
00390         m_ptr->m_type = DEV_NO_STATUS;
00391   }
00392 
00393   /* Almost done. Send back the reply message to the caller. */
00394   if ((status = send(m_ptr->m_source, m_ptr)) != OK) {
00395         panic("TTY","send in do_status failed, status\n", status);
00396   }
00397 }
00398 
00399 /*===========================================================================*
00400  *                              do_read                                      *
00401  *===========================================================================*/
00402 PRIVATE void do_read(tp, m_ptr)
00403 register tty_t *tp;             /* pointer to tty struct */
00404 register message *m_ptr;        /* pointer to message sent to the task */
00405 {
00406 /* A process wants to read from a terminal. */
00407   int r, status;
00408   phys_bytes phys_addr;
00409   int more_verbose= (tp == tty_addr(NR_CONS));
00410 
00411   /* Check if there is already a process hanging in a read, check if the
00412    * parameters are correct, do I/O.
00413    */
00414   if (tp->tty_inleft > 0) {
00415         if (more_verbose) printf("do_read: EIO\n");
00416         r = EIO;
00417   } else
00418   if (m_ptr->COUNT <= 0) {
00419         if (more_verbose) printf("do_read: EINVAL\n");
00420         r = EINVAL;
00421   } else
00422   if (sys_umap(m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,
00423                 &phys_addr) != OK) {
00424         if (more_verbose) printf("do_read: EFAULT\n");
00425         r = EFAULT;
00426   } else {
00427         /* Copy information from the message to the tty struct. */
00428         tp->tty_inrepcode = TASK_REPLY;
00429         tp->tty_incaller = m_ptr->m_source;
00430         tp->tty_inproc = m_ptr->IO_ENDPT;
00431         tp->tty_in_vir = (vir_bytes) m_ptr->ADDRESS;
00432         tp->tty_inleft = m_ptr->COUNT;
00433 
00434         if (!(tp->tty_termios.c_lflag & ICANON)
00435                                         && tp->tty_termios.c_cc[VTIME] > 0) {
00436                 if (tp->tty_termios.c_cc[VMIN] == 0) {
00437                         /* MIN & TIME specify a read timer that finishes the
00438                          * read in TIME/10 seconds if no bytes are available.
00439                          */
00440                         settimer(tp, TRUE);
00441                         tp->tty_min = 1;
00442                 } else {
00443                         /* MIN & TIME specify an inter-byte timer that may
00444                          * have to be cancelled if there are no bytes yet.
00445                          */
00446                         if (tp->tty_eotct == 0) {
00447                                 settimer(tp, FALSE);
00448                                 tp->tty_min = tp->tty_termios.c_cc[VMIN];
00449                         }
00450                 }
00451         }
00452 
00453         /* Anything waiting in the input buffer? Clear it out... */
00454         in_transfer(tp);
00455         /* ...then go back for more. */
00456         handle_events(tp);
00457         if (tp->tty_inleft == 0)  {
00458                 if (tp->tty_select_ops)
00459                         select_retry(tp);
00460                 return;                 /* already done */
00461         }
00462 
00463         /* There were no bytes in the input queue available, so either suspend
00464          * the caller or break off the read if nonblocking.
00465          */
00466         if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
00467                 r = EAGAIN;                             /* cancel the read */
00468                 tp->tty_inleft = tp->tty_incum = 0;
00469         } else {
00470                 r = SUSPEND;                            /* suspend the caller */
00471                 tp->tty_inrepcode = REVIVE;
00472         }
00473   }
00474   if (more_verbose) printf("do_read: replying %d\n", r);
00475   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, r);
00476   if (tp->tty_select_ops)
00477         select_retry(tp);
00478 }
00479 
00480 /*===========================================================================*
00481  *                              do_write                                     *
00482  *===========================================================================*/
00483 PRIVATE void do_write(tp, m_ptr)
00484 register tty_t *tp;
00485 register message *m_ptr;        /* pointer to message sent to the task */
00486 {
00487 /* A process wants to write on a terminal. */
00488   int r;
00489   phys_bytes phys_addr;
00490 
00491   /* Check if there is already a process hanging in a write, check if the
00492    * parameters are correct, do I/O.
00493    */
00494   if (tp->tty_outleft > 0) {
00495         r = EIO;
00496   } else
00497   if (m_ptr->COUNT <= 0) {
00498         r = EINVAL;
00499   } else
00500   if (sys_umap(m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,
00501                 &phys_addr) != OK) {
00502         r = EFAULT;
00503   } else {
00504         /* Copy message parameters to the tty structure. */
00505         tp->tty_outrepcode = TASK_REPLY;
00506         tp->tty_outcaller = m_ptr->m_source;
00507         tp->tty_outproc = m_ptr->IO_ENDPT;
00508         tp->tty_out_vir = (vir_bytes) m_ptr->ADDRESS;
00509         tp->tty_outleft = m_ptr->COUNT;
00510 
00511         /* Try to write. */
00512         handle_events(tp);
00513         if (tp->tty_outleft == 0) 
00514                 return; /* already done */
00515 
00516         /* None or not all the bytes could be written, so either suspend the
00517          * caller or break off the write if nonblocking.
00518          */
00519         if (m_ptr->TTY_FLAGS & O_NONBLOCK) {            /* cancel the write */
00520                 r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
00521                 tp->tty_outleft = tp->tty_outcum = 0;
00522         } else {
00523                 r = SUSPEND;                            /* suspend the caller */
00524                 tp->tty_outrepcode = REVIVE;
00525         }
00526   }
00527   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, r);
00528 }
00529 
00530 /*===========================================================================*
00531  *                              do_ioctl                                     *
00532  *===========================================================================*/
00533 PRIVATE void do_ioctl(tp, m_ptr)
00534 register tty_t *tp;
00535 message *m_ptr;                 /* pointer to message sent to task */
00536 {
00537 /* Perform an IOCTL on this terminal. Posix termios calls are handled
00538  * by the IOCTL system call
00539  */
00540 
00541   int r;
00542   union {
00543         int i;
00544 #if ENABLE_SRCCOMPAT
00545         struct sgttyb sg;
00546         struct tchars tc;
00547 #endif
00548   } param;
00549   size_t size;
00550 
00551   /* Size of the ioctl parameter. */
00552   switch (m_ptr->TTY_REQUEST) {
00553     case TCGETS:        /* Posix tcgetattr function */
00554     case TCSETS:        /* Posix tcsetattr function, TCSANOW option */ 
00555     case TCSETSW:       /* Posix tcsetattr function, TCSADRAIN option */
00556     case TCSETSF:       /* Posix tcsetattr function, TCSAFLUSH option */
00557         size = sizeof(struct termios);
00558         break;
00559 
00560     case TCSBRK:        /* Posix tcsendbreak function */
00561     case TCFLOW:        /* Posix tcflow function */
00562     case TCFLSH:        /* Posix tcflush function */
00563     case TIOCGPGRP:     /* Posix tcgetpgrp function */
00564     case TIOCSPGRP:     /* Posix tcsetpgrp function */
00565         size = sizeof(int);
00566         break;
00567 
00568     case TIOCGWINSZ:    /* get window size (not Posix) */
00569     case TIOCSWINSZ:    /* set window size (not Posix) */
00570         size = sizeof(struct winsize);
00571         break;
00572 
00573 #if ENABLE_SRCCOMPAT
00574     case TIOCGETP:      /* BSD-style get terminal properties */
00575     case TIOCSETP:      /* BSD-style set terminal properties */
00576         size = sizeof(struct sgttyb);
00577         break;
00578 
00579     case TIOCGETC:      /* BSD-style get terminal special characters */ 
00580     case TIOCSETC:      /* BSD-style get terminal special characters */ 
00581         size = sizeof(struct tchars);
00582         break;
00583 #endif
00584 #if (MACHINE == IBM_PC)
00585     case KIOCSMAP:      /* load keymap (Minix extension) */
00586         size = sizeof(keymap_t);
00587         break;
00588 
00589     case TIOCSFON:      /* load font (Minix extension) */
00590         size = sizeof(u8_t [8192]);
00591         break;
00592 
00593 #endif
00594     case TCDRAIN:       /* Posix tcdrain function -- no parameter */
00595     default:            size = 0;
00596   }
00597 
00598   r = OK;
00599   switch (m_ptr->TTY_REQUEST) {
00600     case TCGETS:
00601         /* Get the termios attributes. */
00602         r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_termios,
00603                 m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS, 
00604                 (vir_bytes) size);
00605         break;
00606 
00607     case TCSETSW:
00608     case TCSETSF:
00609     case TCDRAIN:
00610         if (tp->tty_outleft > 0) {
00611                 /* Wait for all ongoing output processing to finish. */
00612                 tp->tty_iocaller = m_ptr->m_source;
00613                 tp->tty_ioproc = m_ptr->IO_ENDPT;
00614                 tp->tty_ioreq = m_ptr->REQUEST;
00615                 tp->tty_iovir = (vir_bytes) m_ptr->ADDRESS;
00616                 r = SUSPEND;
00617                 break;
00618         }
00619         if (m_ptr->TTY_REQUEST == TCDRAIN) break;
00620         if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp);
00621         /*FALL THROUGH*/
00622     case TCSETS:
00623         /* Set the termios attributes. */
00624         r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
00625                 SELF, D, (vir_bytes) &tp->tty_termios, (vir_bytes) size);
00626         if (r != OK) break;
00627         setattr(tp);
00628         break;
00629 
00630     case TCFLSH:
00631         r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
00632                 SELF, D, (vir_bytes) &param.i, (vir_bytes) size);
00633         if (r != OK) break;
00634         switch (param.i) {
00635             case TCIFLUSH:      tty_icancel(tp);                            break;
00636             case TCOFLUSH:      (*tp->tty_ocancel)(tp, 0);                  break;
00637             case TCIOFLUSH:     tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); break;
00638             default:            r = EINVAL;
00639         }
00640         break;
00641 
00642     case TCFLOW:
00643         r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
00644                 SELF, D, (vir_bytes) &param.i, (vir_bytes) size);
00645         if (r != OK) break;
00646         switch (param.i) {
00647             case TCOOFF:
00648             case TCOON:
00649                 tp->tty_inhibited = (param.i == TCOOFF);
00650                 tp->tty_events = 1;
00651                 break;
00652             case TCIOFF:
00653                 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTOP]);
00654                 break;
00655             case TCION:
00656                 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTART]);
00657                 break;
00658             default:
00659                 r = EINVAL;
00660         }
00661         break;
00662 
00663     case TCSBRK:
00664         if (tp->tty_break != NULL) (*tp->tty_break)(tp,0);
00665         break;
00666 
00667     case TIOCGWINSZ:
00668         r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_winsize,
00669                 m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS, 
00670                 (vir_bytes) size);
00671         break;
00672 
00673     case TIOCSWINSZ:
00674         r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
00675                 SELF, D, (vir_bytes) &tp->tty_winsize, (vir_bytes) size);
00676         sigchar(tp, SIGWINCH);
00677         break;
00678 
00679 #if ENABLE_SRCCOMPAT
00680     case TIOCGETP:
00681         compat_getp(tp, &param.sg);
00682         r = sys_vircopy(SELF, D, (vir_bytes) &param.sg,
00683                 m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
00684                 (vir_bytes) size);
00685         break;
00686 
00687     case TIOCSETP:
00688         r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
00689                 SELF, D, (vir_bytes) &param.sg, (vir_bytes) size);
00690         if (r != OK) break;
00691         compat_setp(tp, &param.sg);
00692         break;
00693 
00694     case TIOCGETC:
00695         compat_getc(tp, &param.tc);
00696         r = sys_vircopy(SELF, D, (vir_bytes) &param.tc,
00697                 m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS, 
00698                 (vir_bytes) size);
00699         break;
00700 
00701     case TIOCSETC:
00702         r = sys_vircopy( m_ptr->IO_ENDPT, D, (vir_bytes) m_ptr->ADDRESS,
00703                 SELF, D, (vir_bytes) &param.tc, (vir_bytes) size);
00704         if (r != OK) break;
00705         compat_setc(tp, &param.tc);
00706         break;
00707 #endif
00708 
00709 #if (MACHINE == IBM_PC)
00710     case KIOCSMAP:
00711         /* Load a new keymap (only /dev/console). */
00712         if (isconsole(tp)) r = kbd_loadmap(m_ptr);
00713         break;
00714 
00715     case TIOCSFON:
00716         /* Load a font into an EGA or VGA card (hs@hck.hr) */
00717         if (isconsole(tp)) r = con_loadfont(m_ptr);
00718         break;
00719 #endif
00720 
00721 #if (MACHINE == ATARI)
00722     case VDU_LOADFONT:
00723         r = vdu_loadfont(m_ptr);
00724         break;
00725 #endif
00726 
00727 /* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is 
00728  * not defined.
00729  */
00730     case TIOCGPGRP:     
00731     case TIOCSPGRP:     
00732     default:
00733 #if ENABLE_BINCOMPAT
00734         do_ioctl_compat(tp, m_ptr);
00735         return;
00736 #else
00737         r = ENOTTY;
00738 #endif
00739   }
00740 
00741   /* Send the reply. */
00742   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, r);
00743 }
00744 
00745 /*===========================================================================*
00746  *                              do_open                                      *
00747  *===========================================================================*/
00748 PRIVATE void do_open(tp, m_ptr)
00749 register tty_t *tp;
00750 message *m_ptr;                 /* pointer to message sent to task */
00751 {
00752 /* A tty line has been opened.  Make it the callers controlling tty if
00753  * O_NOCTTY is *not* set and it is not the log device.  1 is returned if
00754  * the tty is made the controlling tty, otherwise OK or an error code.
00755  */
00756   int r = OK;
00757 
00758   if (m_ptr->TTY_LINE == LOG_MINOR) {
00759         /* The log device is a write-only diagnostics device. */
00760         if (m_ptr->COUNT & R_BIT) r = EACCES;
00761   } else {
00762         if (!(m_ptr->COUNT & O_NOCTTY)) {
00763                 tp->tty_pgrp = m_ptr->IO_ENDPT;
00764                 r = 1;
00765         }
00766         tp->tty_openct++;
00767   }
00768   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, r);
00769 }
00770 
00771 /*===========================================================================*
00772  *                              do_close                                     *
00773  *===========================================================================*/
00774 PRIVATE void do_close(tp, m_ptr)
00775 register tty_t *tp;
00776 message *m_ptr;                 /* pointer to message sent to task */
00777 {
00778 /* A tty line has been closed.  Clean up the line if it is the last close. */
00779 
00780   if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) {
00781         tp->tty_pgrp = 0;
00782         tty_icancel(tp);
00783         (*tp->tty_ocancel)(tp, 0);
00784         (*tp->tty_close)(tp, 0);
00785         tp->tty_termios = termios_defaults;
00786         tp->tty_winsize = winsize_defaults;
00787         setattr(tp);
00788   }
00789   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, OK);
00790 }
00791 
00792 /*===========================================================================*
00793  *                              do_cancel                                    *
00794  *===========================================================================*/
00795 PRIVATE void do_cancel(tp, m_ptr)
00796 register tty_t *tp;
00797 message *m_ptr;                 /* pointer to message sent to task */
00798 {
00799 /* A signal has been sent to a process that is hanging trying to read or write.
00800  * The pending read or write must be finished off immediately.
00801  */
00802 
00803   int proc_nr;
00804   int mode;
00805 
00806   /* Check the parameters carefully, to avoid cancelling twice. */
00807   proc_nr = m_ptr->IO_ENDPT;
00808   mode = m_ptr->COUNT;
00809   if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc) {
00810         /* Process was reading when killed.  Clean up input. */
00811         tty_icancel(tp);
00812         tp->tty_inleft = tp->tty_incum = 0;
00813   }
00814   if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc) {
00815         /* Process was writing when killed.  Clean up output. */
00816         (*tp->tty_ocancel)(tp, 0);
00817         tp->tty_outleft = tp->tty_outcum = 0;
00818   }
00819   if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
00820         /* Process was waiting for output to drain. */
00821         tp->tty_ioreq = 0;
00822   }
00823   tp->tty_events = 1;
00824   tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, EINTR);
00825 }
00826 
00827 PUBLIC int select_try(struct tty *tp, int ops)
00828 {
00829         int ready_ops = 0;
00830 
00831         /* Special case. If line is hung up, no operations will block.
00832          * (and it can be seen as an exceptional condition.)
00833          */
00834         if (tp->tty_termios.c_ospeed == B0) {
00835                 ready_ops |= ops;
00836         }
00837 
00838         if (ops & SEL_RD) {
00839                 /* will i/o not block on read? */
00840                 if (tp->tty_inleft > 0) {
00841                         ready_ops |= SEL_RD;    /* EIO - no blocking */
00842                 } else if (tp->tty_incount > 0) {
00843                         /* Is a regular read possible? tty_incount
00844                          * says there is data. But a read will only succeed
00845                          * in canonical mode if a newline has been seen.
00846                          */
00847                         if (!(tp->tty_termios.c_lflag & ICANON) ||
00848                                 tp->tty_eotct > 0) {
00849                                 ready_ops |= SEL_RD;
00850                         }
00851                 }
00852         }
00853 
00854         if (ops & SEL_WR)  {
00855                 if (tp->tty_outleft > 0)  ready_ops |= SEL_WR;
00856                 else if ((*tp->tty_devwrite)(tp, 1)) ready_ops |= SEL_WR;
00857         }
00858         return ready_ops;
00859 }
00860 
00861 PUBLIC int select_retry(struct tty *tp)
00862 {
00863         if (tp->tty_select_ops && select_try(tp, tp->tty_select_ops))
00864                 notify(tp->tty_select_proc);
00865         return OK;
00866 }
00867 
00868 /*===========================================================================*
00869  *                              handle_events                                *
00870  *===========================================================================*/
00871 PUBLIC void handle_events(tp)
00872 tty_t *tp;                      /* TTY to check for events. */
00873 {
00874 /* Handle any events pending on a TTY.  These events are usually device
00875  * interrupts.
00876  *
00877  * Two kinds of events are prominent:
00878  *      - a character has been received from the console or an RS232 line.
00879  *      - an RS232 line has completed a write request (on behalf of a user).
00880  * The interrupt handler may delay the interrupt message at its discretion
00881  * to avoid swamping the TTY task.  Messages may be overwritten when the
00882  * lines are fast or when there are races between different lines, input
00883  * and output, because MINIX only provides single buffering for interrupt
00884  * messages (in proc.c).  This is handled by explicitly checking each line
00885  * for fresh input and completed output on each interrupt.
00886  */
00887   char *buf;
00888   unsigned count;
00889   int status;
00890 
00891   do {
00892         tp->tty_events = 0;
00893 
00894         /* Read input and perform input processing. */
00895         (*tp->tty_devread)(tp, 0);
00896 
00897         /* Perform output processing and write output. */
00898         (*tp->tty_devwrite)(tp, 0);
00899 
00900         /* Ioctl waiting for some event? */
00901         if (tp->tty_ioreq != 0) dev_ioctl(tp);
00902   } while (tp->tty_events);
00903 
00904   /* Transfer characters from the input queue to a waiting process. */
00905   in_transfer(tp);
00906 
00907   /* Reply if enough bytes are available. */
00908   if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
00909         if (tp->tty_inrepcode == REVIVE) {
00910                 notify(tp->tty_incaller);
00911                 tp->tty_inrevived = 1;
00912         } else {
00913                 tty_reply(tp->tty_inrepcode, tp->tty_incaller, 
00914                         tp->tty_inproc, tp->tty_incum);
00915                 tp->tty_inleft = tp->tty_incum = 0;
00916         }
00917   }
00918   if (tp->tty_select_ops)
00919   {
00920         select_retry(tp);
00921   }
00922 #if NR_PTYS > 0
00923   if (ispty(tp))
00924         select_retry_pty(tp);
00925 #endif
00926 }
00927 
00928 /*===========================================================================*
00929  *                              in_transfer                                  *
00930  *===========================================================================*/
00931 PRIVATE void in_transfer(tp)
00932 register tty_t *tp;             /* pointer to terminal to read from */
00933 {
00934 /* Transfer bytes from the input queue to a process reading from a terminal. */
00935 
00936   int ch;
00937   int count;
00938   char buf[64], *bp;
00939 
00940   /* Force read to succeed if the line is hung up, looks like EOF to reader. */
00941   if (tp->tty_termios.c_ospeed == B0) tp->tty_min = 0;
00942 
00943   /* Anything to do? */
00944   if (tp->tty_inleft == 0 || tp->tty_eotct < tp->tty_min) return;
00945 
00946   bp = buf;
00947   while (tp->tty_inleft > 0 && tp->tty_eotct > 0) {
00948         ch = *tp->tty_intail;
00949 
00950         if (!(ch & IN_EOF)) {
00951                 /* One character to be delivered to the user. */
00952                 *bp = ch & IN_CHAR;
00953                 tp->tty_inleft--;
00954                 if (++bp == bufend(buf)) {
00955                         /* Temp buffer full, copy to user space. */
00956                         sys_vircopy(SELF, D, (vir_bytes) buf, 
00957                                 tp->tty_inproc, D, tp->tty_in_vir,
00958                                 (vir_bytes) buflen(buf));
00959                         tp->tty_in_vir += buflen(buf);
00960                         tp->tty_incum += buflen(buf);
00961                         bp = buf;
00962                 }
00963         }
00964 
00965         /* Remove the character from the input queue. */
00966         if (++tp->tty_intail == bufend(tp->tty_inbuf))
00967                 tp->tty_intail = tp->tty_inbuf;
00968         tp->tty_incount--;
00969         if (ch & IN_EOT) {
00970                 tp->tty_eotct--;
00971                 /* Don't read past a line break in canonical mode. */
00972                 if (tp->tty_termios.c_lflag & ICANON) tp->tty_inleft = 0;
00973         }
00974   }
00975 
00976   if (bp > buf) {
00977         /* Leftover characters in the buffer. */
00978         count = bp - buf;
00979         sys_vircopy(SELF, D, (vir_bytes) buf, 
00980                 tp->tty_inproc, D, tp->tty_in_vir, (vir_bytes) count);
00981         tp->tty_in_vir += count;
00982         tp->tty_incum += count;
00983   }
00984 
00985   /* Usually reply to the reader, possibly even if incum == 0 (EOF). */
00986   if (tp->tty_inleft == 0) {
00987         if (tp->tty_inrepcode == REVIVE) {
00988                 notify(tp->tty_incaller);
00989                 tp->tty_inrevived = 1;
00990         } else {
00991                 tty_reply(tp->tty_inrepcode, tp->tty_incaller, 
00992                         tp->tty_inproc, tp->tty_incum);
00993                 tp->tty_inleft = tp->tty_incum = 0;
00994         }
00995   }
00996 }
00997 
00998 /*===========================================================================*
00999  *                              in_process                                   *
01000  *===========================================================================*/
01001 PUBLIC int in_process(tp, buf, count)
01002 register tty_t *tp;             /* terminal on which character has arrived */
01003 char *buf;                      /* buffer with input characters */
01004 int count;                      /* number of input characters */
01005 {
01006 /* Characters have just been typed in.  Process, save, and echo them.  Return
01007  * the number of characters processed.
01008  */
01009 
01010   int ch, sig, ct;
01011   int timeset = FALSE;
01012   static unsigned char csize_mask[] = { 0x1F, 0x3F, 0x7F, 0xFF };
01013 
01014   for (ct = 0; ct < count; ct++) {
01015         /* Take one character. */
01016         ch = *buf++ & BYTE;
01017 
01018         /* Strip to seven bits? */
01019         if (tp->tty_termios.c_iflag & ISTRIP) ch &= 0x7F;
01020 
01021         /* Input extensions? */
01022         if (tp->tty_termios.c_lflag & IEXTEN) {
01023 
01024                 /* Previous character was a character escape? */
01025                 if (tp->tty_escaped) {
01026                         tp->tty_escaped = NOT_ESCAPED;
01027                         ch |= IN_ESC;   /* protect character */
01028                 }
01029 
01030                 /* LNEXT (^V) to escape the next character? */
01031                 if (ch == tp->tty_termios.c_cc[VLNEXT]) {
01032                         tp->tty_escaped = ESCAPED;
01033                         rawecho(tp, '^');
01034                         rawecho(tp, '\b');
01035                         continue;       /* do not store the escape */
01036                 }
01037 
01038                 /* REPRINT (^R) to reprint echoed characters? */
01039                 if (ch == tp->tty_termios.c_cc[VREPRINT]) {
01040                         reprint(tp);
01041                         continue;
01042                 }
01043         }
01044 
01045         /* _POSIX_VDISABLE is a normal character value, so better escape it. */
01046         if (ch == _POSIX_VDISABLE) ch |= IN_ESC;
01047 
01048         /* Map CR to LF, ignore CR, or map LF to CR. */
01049         if (ch == '\r') {
01050                 if (tp->tty_termios.c_iflag & IGNCR) continue;
01051                 if (tp->tty_termios.c_iflag & ICRNL) ch = '\n';
01052         } else
01053         if (ch == '\n') {
01054                 if (tp->tty_termios.c_iflag & INLCR) ch = '\r';
01055         }
01056 
01057         /* Canonical mode? */
01058         if (tp->tty_termios.c_lflag & ICANON) {
01059 
01060                 /* Erase processing (rub out of last character). */
01061                 if (ch == tp->tty_termios.c_cc[VERASE]) {
01062                         (void) back_over(tp);
01063                         if (!(tp->tty_termios.c_lflag & ECHOE)) {
01064                                 (void) tty_echo(tp, ch);
01065                         }
01066                         continue;
01067                 }
01068 
01069                 /* Kill processing (remove current line). */
01070                 if (ch == tp->tty_termios.c_cc[VKILL]) {
01071                         while (back_over(tp)) {}
01072                         if (!(tp->tty_termios.c_lflag & ECHOE)) {
01073                                 (void) tty_echo(tp, ch);
01074                                 if (tp->tty_termios.c_lflag & ECHOK)
01075                                         rawecho(tp, '\n');
01076                         }
01077                         continue;
01078                 }
01079 
01080                 /* EOF (^D) means end-of-file, an invisible "line break". */
01081                 if (ch == tp->tty_termios.c_cc[VEOF]) ch |= IN_EOT | IN_EOF;
01082 
01083                 /* The line may be returned to the user after an LF. */
01084                 if (ch == '\n') ch |= IN_EOT;
01085 
01086                 /* Same thing with EOL, whatever it may be. */
01087                 if (ch == tp->tty_termios.c_cc[VEOL]) ch |= IN_EOT;
01088         }
01089 
01090         /* Start/stop input control? */
01091         if (tp->tty_termios.c_iflag & IXON) {
01092 
01093                 /* Output stops on STOP (^S). */
01094                 if (ch == tp->tty_termios.c_cc[VSTOP]) {
01095                         tp->tty_inhibited = STOPPED;
01096                         tp->tty_events = 1;
01097                         continue;
01098                 }
01099 
01100                 /* Output restarts on START (^Q) or any character if IXANY. */
01101                 if (tp->tty_inhibited) {
01102                         if (ch == tp->tty_termios.c_cc[VSTART]
01103                                         || (tp->tty_termios.c_iflag & IXANY)) {
01104                                 tp->tty_inhibited = RUNNING;
01105                                 tp->tty_events = 1;
01106                                 if (ch == tp->tty_termios.c_cc[VSTART])
01107                                         continue;
01108                         }
01109                 }
01110         }
01111 
01112         if (tp->tty_termios.c_lflag & ISIG) {
01113                 /* Check for INTR (^?) and QUIT (^\) characters. */
01114                 if (ch == tp->tty_termios.c_cc[VINTR]
01115                                         || ch == tp->tty_termios.c_cc[VQUIT]) {
01116                         sig = SIGINT;
01117                         if (ch == tp->tty_termios.c_cc[VQUIT]) sig = SIGQUIT;
01118                         sigchar(tp, sig);
01119                         (void) tty_echo(tp, ch);
01120                         continue;
01121                 }
01122         }
01123 
01124         /* Is there space in the input buffer? */
01125         if (tp->tty_incount == buflen(tp->tty_inbuf)) {
01126                 /* No space; discard in canonical mode, keep in raw mode. */
01127                 if (tp->tty_termios.c_lflag & ICANON) continue;
01128                 break;
01129         }
01130 
01131         if (!(tp->tty_termios.c_lflag & ICANON)) {
01132                 /* In raw mode all characters are "line breaks". */
01133                 ch |= IN_EOT;
01134 
01135                 /* Start an inter-byte timer? */
01136                 if (!timeset && tp->tty_termios.c_cc[VMIN] > 0
01137                                 && tp->tty_termios.c_cc[VTIME] > 0) {
01138                         settimer(tp, TRUE);
01139                         timeset = TRUE;
01140                 }
01141         }
01142 
01143         /* Perform the intricate function of echoing. */
01144         if (tp->tty_termios.c_lflag & (ECHO|ECHONL)) ch = tty_echo(tp, ch);
01145 
01146         /* Save the character in the input queue. */
01147         *tp->tty_inhead++ = ch;
01148         if (tp->tty_inhead == bufend(tp->tty_inbuf))
01149                 tp->tty_inhead = tp->tty_inbuf;
01150         tp->tty_incount++;
01151         if (ch & IN_EOT) tp->tty_eotct++;
01152 
01153         /* Try to finish input if the queue threatens to overflow. */
01154         if (tp->tty_incount == buflen(tp->tty_inbuf)) in_transfer(tp);
01155   }
01156   return ct;
01157 }
01158 
01159 /*===========================================================================*
01160  *                              echo                                         *
01161  *===========================================================================*/
01162 PRIVATE int tty_echo(tp, ch)
01163 register tty_t *tp;             /* terminal on which to echo */
01164 register int ch;                /* pointer to character to echo */
01165 {
01166 /* Echo the character if echoing is on.  Some control characters are echoed
01167  * with their normal effect, other control characters are echoed as "^X",
01168  * normal characters are echoed normally.  EOF (^D) is echoed, but immediately
01169  * backspaced over.  Return the character with the echoed length added to its
01170  * attributes.
01171  */
01172   int len, rp;
01173 
01174   ch &= ~IN_LEN;
01175   if (!(tp->tty_termios.c_lflag & ECHO)) {
01176         if (ch == ('\n' | IN_EOT) && (tp->tty_termios.c_lflag
01177                                         & (ICANON|ECHONL)) == (ICANON|ECHONL))
01178                 (*tp->tty_echo)(tp, '\n');
01179         return(ch);
01180   }
01181 
01182   /* "Reprint" tells if the echo output has been messed up by other output. */
01183   rp = tp->tty_incount == 0 ? FALSE : tp->tty_reprint;
01184 
01185   if ((ch & IN_CHAR) < ' ') {
01186         switch (ch & (IN_ESC|IN_EOF|IN_EOT|IN_CHAR)) {
01187             case '\t':
01188                 len = 0;
01189                 do {
01190                         (*tp->tty_echo)(tp, ' ');
01191                         len++;
01192                 } while (len < TAB_SIZE && (tp->tty_position & TAB_MASK) != 0);
01193                 break;
01194             case '\r' | IN_EOT:
01195             case '\n' | IN_EOT:
01196                 (*tp->tty_echo)(tp, ch & IN_CHAR);
01197                 len = 0;
01198                 break;
01199             default:
01200                 (*tp->tty_echo)(tp, '^');
01201                 (*tp->tty_echo)(tp, '@' + (ch & IN_CHAR));
01202                 len = 2;
01203         }
01204   } else
01205   if ((ch & IN_CHAR) == '\177') {
01206         /* A DEL prints as "^?". */
01207         (*tp->tty_echo)(tp, '^');
01208         (*tp->tty_echo)(tp, '?');
01209         len = 2;
01210   } else {
01211         (*tp->tty_echo)(tp, ch & IN_CHAR);
01212         len = 1;
01213   }
01214   if (ch & IN_EOF) while (len > 0) { (*tp->tty_echo)(tp, '\b'); len--; }
01215 
01216   tp->tty_reprint = rp;
01217   return(ch | (len << IN_LSHIFT));
01218 }
01219 
01220 /*===========================================================================*
01221  *                              rawecho                                      *
01222  *===========================================================================*/
01223 PRIVATE void rawecho(tp, ch)
01224 register tty_t *tp;
01225 int ch;
01226 {
01227 /* Echo without interpretation if ECHO is set. */
01228   int rp = tp->tty_reprint;
01229   if (tp->tty_termios.c_lflag & ECHO) (*tp->tty_echo)(tp, ch);
01230   tp->tty_reprint = rp;
01231 }
01232 
01233 /*===========================================================================*
01234  *                              back_over                                    *
01235  *===========================================================================*/
01236 PRIVATE int back_over(tp)
01237 register tty_t *tp;
01238 {
01239 /* Backspace to previous character on screen and erase it. */
01240   u16_t *head;
01241   int len;
01242 
01243   if (tp->tty_incount == 0) return(0);  /* queue empty */
01244   head = tp->tty_inhead;
01245   if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
01246   if (*--head & IN_EOT) return(0);              /* can't erase "line breaks" */
01247   if (tp->tty_reprint) reprint(tp);             /* reprint if messed up */
01248   tp->tty_inhead = head;
01249   tp->tty_incount--;
01250   if (tp->tty_termios.c_lflag & ECHOE) {
01251         len = (*head & IN_LEN) >> IN_LSHIFT;
01252         while (len > 0) {
01253                 rawecho(tp, '\b');
01254                 rawecho(tp, ' ');
01255                 rawecho(tp, '\b');
01256                 len--;
01257         }
01258   }
01259   return(1);                            /* one character erased */
01260 }
01261 
01262 /*===========================================================================*
01263  *                              reprint                                      *
01264  *===========================================================================*/
01265 PRIVATE void reprint(tp)
01266 register tty_t *tp;             /* pointer to tty struct */
01267 {
01268 /* Restore what has been echoed to screen before if the user input has been
01269  * messed up by output, or if REPRINT (^R) is typed.
01270  */
01271   int count;
01272   u16_t *head;
01273 
01274   tp->tty_reprint = FALSE;
01275 
01276   /* Find the last line break in the input. */
01277   head = tp->tty_inhead;
01278   count = tp->tty_incount;
01279   while (count > 0) {
01280         if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
01281         if (head[-1] & IN_EOT) break;
01282         head--;
01283         count--;
01284   }
01285   if (count == tp->tty_incount) return;         /* no reason to reprint */
01286 
01287   /* Show REPRINT (^R) and move to a new line. */
01288   (void) tty_echo(tp, tp->tty_termios.c_cc[VREPRINT] | IN_ESC);
01289   rawecho(tp, '\r');
01290   rawecho(tp, '\n');
01291 
01292   /* Reprint from the last break onwards. */
01293   do {
01294         if (head == bufend(tp->tty_inbuf)) head = tp->tty_inbuf;
01295         *head = tty_echo(tp, *head);
01296         head++;
01297         count++;
01298   } while (count < tp->tty_incount);
01299 }
01300 
01301 /*===========================================================================*
01302  *                              out_process                                  *
01303  *===========================================================================*/
01304 PUBLIC void out_process(tp, bstart, bpos, bend, icount, ocount)
01305 tty_t *tp;
01306 char *bstart, *bpos, *bend;     /* start/pos/end of circular buffer */
01307 int *icount;                    /* # input chars / input chars used */
01308 int *ocount;                    /* max output chars / output chars used */
01309 {
01310 /* Perform output processing on a circular buffer.  *icount is the number of
01311  * bytes to process, and the number of bytes actually processed on return.
01312  * *ocount is the space available on input and the space used on output.
01313  * (Naturally *icount < *ocount.)  The column position is updated modulo
01314  * the TAB size, because we really only need it for tabs.
01315  */
01316 
01317   int tablen;
01318   int ict = *icount;
01319   int oct = *ocount;
01320   int pos = tp->tty_position;
01321 
01322   while (ict > 0) {
01323         switch (*bpos) {
01324         case '\7':
01325                 break;
01326         case '\b':
01327                 pos--;
01328                 break;
01329         case '\r':
01330                 pos = 0;
01331                 break;
01332         case '\n':
01333                 if ((tp->tty_termios.c_oflag & (OPOST|ONLCR))
01334                                                         == (OPOST|ONLCR)) {
01335                         /* Map LF to CR+LF if there is space.  Note that the
01336                          * next character in the buffer is overwritten, so
01337                          * we stop at this point.
01338                          */
01339                         if (oct >= 2) {
01340                                 *bpos = '\r';
01341                                 if (++bpos == bend) bpos = bstart;
01342                                 *bpos = '\n';
01343                                 pos = 0;
01344                                 ict--;
01345                                 oct -= 2;
01346                         }
01347                         goto out_done;  /* no space or buffer got changed */
01348                 }
01349                 break;
01350         case '\t':
01351                 /* Best guess for the tab length. */
01352                 tablen = TAB_SIZE - (pos & TAB_MASK);
01353 
01354                 if ((tp->tty_termios.c_oflag & (OPOST|XTABS))
01355                                                         == (OPOST|XTABS)) {
01356                         /* Tabs must be expanded. */
01357                         if (oct >= tablen) {
01358                                 pos += tablen;
01359                                 ict--;
01360                                 oct -= tablen;
01361                                 do {
01362                                         *bpos = ' ';
01363                                         if (++bpos == bend) bpos = bstart;
01364                                 } while (--tablen != 0);
01365                         }
01366                         goto out_done;
01367                 }
01368                 /* Tabs are output directly. */
01369                 pos += tablen;
01370                 break;
01371         default:
01372                 /* Assume any other character prints as one character. */
01373                 pos++;
01374         }
01375         if (++bpos == bend) bpos = bstart;
01376         ict--;
01377         oct--;
01378   }
01379 out_done:
01380   tp->tty_position = pos & TAB_MASK;
01381 
01382   *icount -= ict;       /* [io]ct are the number of chars not used */
01383   *ocount -= oct;       /* *[io]count are the number of chars that are used */
01384 }
01385 
01386 /*===========================================================================*
01387  *                              dev_ioctl                                    *
01388  *===========================================================================*/
01389 PRIVATE void dev_ioctl(tp)
01390 tty_t *tp;
01391 {
01392 /* The ioctl's TCSETSW, TCSETSF and TCDRAIN wait for output to finish to make
01393  * sure that an attribute change doesn't affect the processing of current
01394  * output.  Once output finishes the ioctl is executed as in do_ioctl().
01395  */
01396   int result;
01397 
01398   if (tp->tty_outleft > 0) return;              /* output not finished */
01399 
01400   if (tp->tty_ioreq != TCDRAIN) {
01401         if (tp->tty_ioreq == TCSETSF) tty_icancel(tp);
01402         result = sys_vircopy(tp->tty_ioproc, D, tp->tty_iovir,
01403                         SELF, D, (vir_bytes) &tp->tty_termios,
01404                         (vir_bytes) sizeof(tp->tty_termios));
01405         setattr(tp);
01406   }
01407   tp->tty_ioreq = 0;
01408   tty_reply(REVIVE, tp->tty_iocaller, tp->tty_ioproc, result);
01409 }
01410 
01411 /*===========================================================================*
01412  *                              setattr                                      *
01413  *===========================================================================*/
01414 PRIVATE void setattr(tp)
01415 tty_t *tp;
01416 {
01417 /* Apply the new line attributes (raw/canonical, line speed, etc.) */
01418   u16_t *inp;
01419   int count;
01420 
01421   if (!(tp->tty_termios.c_lflag & ICANON)) {
01422         /* Raw mode; put a "line break" on all characters in the input queue.
01423          * It is undefined what happens to the input queue when ICANON is
01424          * switched off, a process should use TCSAFLUSH to flush the queue.
01425          * Keeping the queue to preserve typeahead is the Right Thing, however
01426          * when a process does use TCSANOW to switch to raw mode.
01427          */
01428         count = tp->tty_eotct = tp->tty_incount;
01429         inp = tp->tty_intail;
01430         while (count > 0) {
01431                 *inp |= IN_EOT;
01432                 if (++inp == bufend(tp->tty_inbuf)) inp = tp->tty_inbuf;
01433                 --count;
01434         }
01435   }
01436 
01437   /* Inspect MIN and TIME. */
01438   settimer(tp, FALSE);
01439   if (tp->tty_termios.c_lflag & ICANON) {
01440         /* No MIN & TIME in canonical mode. */
01441         tp->tty_min = 1;
01442   } else {
01443         /* In raw mode MIN is the number of chars wanted, and TIME how long
01444          * to wait for them.  With interesting exceptions if either is zero.
01445          */
01446         tp->tty_min = tp->tty_termios.c_cc[VMIN];
01447         if (tp->tty_min == 0 && tp->tty_termios.c_cc[VTIME] > 0)
01448                 tp->tty_min = 1;
01449   }
01450 
01451   if (!(tp->tty_termios.c_iflag & IXON)) {
01452         /* No start/stop output control, so don't leave output inhibited. */
01453         tp->tty_inhibited = RUNNING;
01454         tp->tty_events = 1;
01455   }
01456 
01457   /* Setting the output speed to zero hangs up the phone. */
01458   if (tp->tty_termios.c_ospeed == B0) sigchar(tp, SIGHUP);
01459 
01460   /* Set new line speed, character size, etc at the device level. */
01461   (*tp->tty_ioctl)(tp, 0);
01462 }
01463 
01464 /*===========================================================================*
01465  *                              tty_reply                                    *
01466  *===========================================================================*/
01467 PUBLIC void tty_reply(code, replyee, proc_nr, status)
01468 int code;                       /* TASK_REPLY or REVIVE */
01469 int replyee;                    /* destination address for the reply */
01470 int proc_nr;                    /* to whom should the reply go? */
01471 int status;                     /* reply code */
01472 {
01473 /* Send a reply to a process that wanted to read or write data. */
01474   message tty_mess;
01475 
01476   tty_mess.m_type = code;
01477   tty_mess.REP_ENDPT = proc_nr;
01478   tty_mess.REP_STATUS = status;
01479 
01480   if ((status = send(replyee, &tty_mess)) != OK) {
01481         printf("TTY: couldn't reply to %d\n", replyee);
01482         panic("TTY","tty_reply failed, status\n", status);
01483   }
01484 }
01485 
01486 /*===========================================================================*
01487  *                              sigchar                                      *
01488  *===========================================================================*/
01489 PUBLIC void sigchar(tp, sig)
01490 register tty_t *tp;
01491 int sig;                        /* SIGINT, SIGQUIT, SIGKILL or SIGHUP */
01492 {
01493 /* Process a SIGINT, SIGQUIT or SIGKILL char from the keyboard or SIGHUP from
01494  * a tty close, "stty 0", or a real RS-232 hangup.  MM will send the signal to
01495  * the process group (INT, QUIT), all processes (KILL), or the session leader
01496  * (HUP).
01497  */
01498   int status;
01499 
01500   if (tp->tty_pgrp != 0) 
01501       if (OK != (status = sys_kill(tp->tty_pgrp, sig)))
01502         panic("TTY","Error, call to sys_kill failed", status);
01503 
01504   if (!(tp->tty_termios.c_lflag & NOFLSH)) {
01505         tp->tty_incount = tp->tty_eotct = 0;    /* kill earlier input */
01506         tp->tty_intail = tp->tty_inhead;
01507         (*tp->tty_ocancel)(tp, 0);                      /* kill all output */
01508         tp->tty_inhibited = RUNNING;
01509         tp->tty_events = 1;
01510   }
01511 }
01512 
01513 /*===========================================================================*
01514  *                              tty_icancel                                  *
01515  *===========================================================================*/
01516 PRIVATE void tty_icancel(tp)
01517 register tty_t *tp;
01518 {
01519 /* Discard all pending input, tty buffer or device. */
01520 
01521   tp->tty_incount = tp->tty_eotct = 0;
01522   tp->tty_intail = tp->tty_inhead;
01523   (*tp->tty_icancel)(tp, 0);
01524 }
01525 
01526 /*===========================================================================*
01527  *                              tty_init                                     *
01528  *===========================================================================*/
01529 PRIVATE void tty_init()
01530 {
01531 /* Initialize tty structure and call device initialization routines. */
01532 
01533   register tty_t *tp;
01534   int s;
01535   struct sigaction sa;
01536 
01537   /* Initialize the terminal lines. */
01538   for (tp = FIRST_TTY,s=0; tp < END_TTY; tp++,s++) {
01539 
01540         tp->tty_index = s;
01541 
01542         tmr_inittimer(&tp->tty_tmr);
01543 
01544         tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
01545         tp->tty_min = 1;
01546         tp->tty_termios = termios_defaults;
01547         tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
01548                                                                 tty_devnop;
01549         if (tp < tty_addr(NR_CONS)) {
01550                 scr_init(tp);
01551 
01552                 /* Initialize the keyboard driver. */
01553                 kb_init(tp);
01554 
01555                 tp->tty_minor = CONS_MINOR + s;
01556         } else
01557         if (tp < tty_addr(NR_CONS+NR_RS_LINES)) {
01558                 rs_init(tp);
01559                 tp->tty_minor = RS232_MINOR + s-NR_CONS;
01560         } else {
01561                 pty_init(tp);
01562                 tp->tty_minor = s - (NR_CONS+NR_RS_LINES) + TTYPX_MINOR;
01563         }
01564   }
01565 
01566 #if DEAD_CODE
01567   /* Install signal handlers. Ask PM to transform signal into message. */
01568   sa.sa_handler = SIG_MESS;
01569   sigemptyset(&sa.sa_mask);
01570   sa.sa_flags = 0;
01571   if (sigaction(SIGTERM,&sa,NULL)<0) panic("TTY","sigaction failed", errno);
01572   if (sigaction(SIGKMESS,&sa,NULL)<0) panic("TTY","sigaction failed", errno);
01573   if (sigaction(SIGKSTOP,&sa,NULL)<0) panic("TTY","sigaction failed", errno);
01574 #endif
01575 #if DEBUG
01576         printf("end of tty_init\n");
01577 #endif
01578 }
01579 
01580 /*===========================================================================*
01581  *                              tty_timed_out                                *
01582  *===========================================================================*/
01583 PRIVATE void tty_timed_out(timer_t *tp)
01584 {
01585 /* This timer has expired. Set the events flag, to force processing. */
01586   tty_t *tty_ptr;
01587   tty_ptr = &tty_table[tmr_arg(tp)->ta_int];
01588   tty_ptr->tty_min = 0;                 /* force read to succeed */
01589   tty_ptr->tty_events = 1;              
01590 }
01591 
01592 /*===========================================================================*
01593  *                              expire_timers                                *
01594  *===========================================================================*/
01595 PRIVATE void expire_timers(void)
01596 {
01597 /* A synchronous alarm message was received. Check if there are any expired 
01598  * timers. Possibly set the event flag and reschedule another alarm.  
01599  */
01600   clock_t now;                          /* current time */
01601   int s;
01602 
01603   /* Get the current time to compare the timers against. */
01604   if ((s=getuptime(&now)) != OK)
01605         panic("TTY","Couldn't get uptime from clock.", s);
01606 
01607   /* Scan the queue of timers for expired timers. This dispatch the watchdog
01608    * functions of expired timers. Possibly a new alarm call must be scheduled.
01609    */
01610   tmrs_exptimers(&tty_timers, now, NULL);
01611   if (tty_timers == NULL) tty_next_timeout = TMR_NEVER;
01612   else {                                          /* set new sync alarm */
01613         tty_next_timeout = tty_timers->tmr_exp_time;
01614         if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
01615                 panic("TTY","Couldn't set synchronous alarm.", s);
01616   }
01617 }
01618 
01619 /*===========================================================================*
01620  *                              settimer                                     *
01621  *===========================================================================*/
01622 PRIVATE void settimer(tty_ptr, enable)
01623 tty_t *tty_ptr;                 /* line to set or unset a timer on */
01624 int enable;                     /* set timer if true, otherwise unset */
01625 {
01626   clock_t now;                          /* current time */
01627   clock_t exp_time;
01628   int s;
01629 
01630   /* Get the current time to calculate the timeout time. */
01631   if ((s=getuptime(&now)) != OK)
01632         panic("TTY","Couldn't get uptime from clock.", s);
01633   if (enable) {
01634         exp_time = now + tty_ptr->tty_termios.c_cc[VTIME] * (HZ/10);
01635         /* Set a new timer for enabling the TTY events flags. */
01636         tmrs_settimer(&tty_timers, &tty_ptr->tty_tmr, 
01637                 exp_time, tty_timed_out, NULL);  
01638   } else {
01639         /* Remove the timer from the active and expired lists. */
01640         tmrs_clrtimer(&tty_timers, &tty_ptr->tty_tmr, NULL);
01641   }
01642   
01643   /* Now check if a new alarm must be scheduled. This happens when the front
01644    * of the timers queue was disabled or reinserted at another position, or
01645    * when a new timer was added to the front.
01646    */
01647   if (tty_timers == NULL) tty_next_timeout = TMR_NEVER;
01648   else if (tty_timers->tmr_exp_time != tty_next_timeout) { 
01649         tty_next_timeout = tty_timers->tmr_exp_time;
01650         if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
01651                 panic("TTY","Couldn't set synchronous alarm.", s);
01652   }
01653 }
01654 
01655 /*===========================================================================*
01656  *                              tty_devnop                                   *
01657  *===========================================================================*/
01658 PUBLIC int tty_devnop(tp, try)
01659 tty_t *tp;
01660 int try;
01661 {
01662   /* Some functions need not be implemented at the device level. */
01663 }
01664 
01665 /*===========================================================================*
01666  *                              do_select                                    *
01667  *===========================================================================*/
01668 PRIVATE void do_select(tp, m_ptr)
01669 register tty_t *tp;             /* pointer to tty struct */
01670 register message *m_ptr;        /* pointer to message sent to the task */
01671 {
01672         int ops, ready_ops = 0, watch;
01673 
01674         ops = m_ptr->IO_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
01675         watch = (m_ptr->IO_ENDPT & SEL_NOTIFY) ? 1 : 0;
01676 
01677         ready_ops = select_try(tp, ops);
01678 
01679         if (!ready_ops && ops && watch) {
01680                 tp->tty_select_ops |= ops;
01681                 tp->tty_select_proc = m_ptr->m_source;
01682         }
01683 
01684         tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, ready_ops);
01685 
01686         return;
01687 }
01688 
01689 #if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
01690 /*===========================================================================*
01691  *                              compat_getp                                  *
01692  *===========================================================================*/
01693 PRIVATE int compat_getp(tp, sg)
01694 tty_t *tp;
01695 struct sgttyb *sg;
01696 {
01697 /* Translate an old TIOCGETP to the termios equivalent. */
01698   int flgs;
01699 
01700   sg->sg_erase = tp->tty_termios.c_cc[VERASE];
01701   sg->sg_kill = tp->tty_termios.c_cc[VKILL];
01702   sg->sg_ospeed = tspd2sgspd(cfgetospeed(&tp->tty_termios));
01703   sg->sg_ispeed = tspd2sgspd(cfgetispeed(&tp->tty_termios));
01704 
01705   flgs = 0;
01706 
01707   /* XTABS      - if OPOST and XTABS */
01708   if ((tp->tty_termios.c_oflag & (OPOST|XTABS)) == (OPOST|XTABS))
01709         flgs |= 0006000;
01710 
01711   /* BITS5..BITS8  - map directly to CS5..CS8 */
01712   flgs |= (tp->tty_termios.c_cflag & CSIZE) << (8-2);
01713 
01714   /* EVENP      - if PARENB and not PARODD */
01715   if ((tp->tty_termios.c_cflag & (PARENB|PARODD)) == PARENB)
01716         flgs |= 0000200;
01717 
01718   /* ODDP       - if PARENB and PARODD */
01719   if ((tp->tty_termios.c_cflag & (PARENB|PARODD)) == (PARENB|PARODD))
01720         flgs |= 0000100;
01721 
01722   /* RAW        - if not ICANON and not ISIG */
01723   if (!(tp->tty_termios.c_lflag & (ICANON|ISIG)))
01724         flgs |= 0000040;
01725 
01726   /* CRMOD      - if ICRNL */
01727   if (tp->tty_termios.c_iflag & ICRNL)
01728         flgs |= 0000020;
01729 
01730   /* ECHO       - if ECHO */
01731   if (tp->tty_termios.c_lflag & ECHO)
01732         flgs |= 0000010;
01733 
01734   /* CBREAK     - if not ICANON and ISIG */
01735   if ((tp->tty_termios.c_lflag & (ICANON|ISIG)) == ISIG)
01736         flgs |= 0000002;
01737 
01738   sg->sg_flags = flgs;
01739   return(OK);
01740 }
01741 
01742 /*===========================================================================*
01743  *                              compat_getc                                  *
01744  *===========================================================================*/
01745 PRIVATE int compat_getc(tp, tc)
01746 tty_t *tp;
01747 struct tchars *tc;
01748 {
01749 /* Translate an old TIOCGETC to the termios equivalent. */
01750 
01751   tc->t_intrc = tp->tty_termios.c_cc[VINTR];
01752   tc->t_quitc = tp->tty_termios.c_cc[VQUIT];
01753   tc->t_startc = tp->tty_termios.c_cc[VSTART];
01754   tc->t_stopc = tp->tty_termios.c_cc[VSTOP];
01755   tc->t_brkc = tp->tty_termios.c_cc[VEOL];
01756   tc->t_eofc = tp->tty_termios.c_cc[VEOF];
01757   return(OK);
01758 }
01759 
01760 /*===========================================================================*
01761  *                              compat_setp                                  *
01762  *===========================================================================*/
01763 PRIVATE int compat_setp(tp, sg)
01764 tty_t *tp;
01765 struct sgttyb *sg;
01766 {
01767 /* Translate an old TIOCSETP to the termios equivalent. */
01768   struct termios termios;
01769   int flags;
01770 
01771   termios = tp->tty_termios;
01772 
01773   termios.c_cc[VERASE] = sg->sg_erase;
01774   termios.c_cc[VKILL] = sg->sg_kill;
01775   cfsetispeed(&termios, sgspd2tspd(sg->sg_ispeed & BYTE));
01776   cfsetospeed(&termios, sgspd2tspd(sg->sg_ospeed & BYTE));
01777   flags = sg->sg_flags;
01778 
01779   /* Input flags */
01780 
01781   /* BRKINT     - not changed */
01782   /* ICRNL      - set if CRMOD is set and not RAW */
01783   /*              (CRMOD also controls output) */
01784   termios.c_iflag &= ~ICRNL;
01785   if ((flags & 0000020) && !(flags & 0000040))
01786         termios.c_iflag |= ICRNL;
01787 
01788   /* IGNBRK     - not changed */
01789   /* IGNCR      - forced off (ignoring cr's is not supported) */
01790   termios.c_iflag &= ~IGNCR;
01791 
01792   /* IGNPAR     - not changed */
01793   /* INLCR      - forced off (mapping nl's to cr's is not supported) */
01794   termios.c_iflag &= ~INLCR;
01795 
01796   /* INPCK      - not changed */
01797   /* ISTRIP     - not changed */
01798   /* IXOFF      - not changed */
01799   /* IXON       - forced on if not RAW */
01800   termios.c_iflag &= ~IXON;
01801   if (!(flags & 0000040))
01802         termios.c_iflag |= IXON;
01803 
01804   /* PARMRK     - not changed */
01805 
01806   /* Output flags */
01807 
01808   /* OPOST      - forced on if not RAW */
01809   termios.c_oflag &= ~OPOST;
01810   if (!(flags & 0000040))
01811         termios.c_oflag |= OPOST;
01812 
01813   /* ONLCR      - forced on if CRMOD */
01814   termios.c_oflag &= ~ONLCR;
01815   if (flags & 0000020)
01816         termios.c_oflag |= ONLCR;
01817 
01818   /* XTABS      - forced on if XTABS */
01819   termios.c_oflag &= ~XTABS;
01820   if (flags & 0006000)
01821         termios.c_oflag |= XTABS;
01822 
01823   /* CLOCAL     - not changed */
01824   /* CREAD      - forced on (receiver is always enabled) */
01825   termios.c_cflag |= CREAD;
01826 
01827   /* CSIZE      - CS5-CS8 correspond directly to BITS5-BITS8 */
01828   termios.c_cflag = (termios.c_cflag & ~CSIZE) | ((flags & 0001400) >> (8-2));
01829 
01830   /* CSTOPB     - not changed */
01831   /* HUPCL      - not changed */
01832   /* PARENB     - set if EVENP or ODDP is set */
01833   termios.c_cflag &= ~PARENB;
01834   if (flags & (0000200|0000100))
01835         termios.c_cflag |= PARENB;
01836 
01837   /* PARODD     - set if ODDP is set */
01838   termios.c_cflag &= ~PARODD;
01839   if (flags & 0000100)
01840         termios.c_cflag |= PARODD;
01841 
01842   /* Local flags */
01843 
01844   /* ECHO               - set if ECHO is set */
01845   termios.c_lflag &= ~ECHO;
01846   if (flags & 0000010)
01847         termios.c_lflag |= ECHO;
01848 
01849   /* ECHOE      - not changed */
01850   /* ECHOK      - not changed */
01851   /* ECHONL     - not changed */
01852   /* ICANON     - set if neither CBREAK nor RAW */
01853   termios.c_lflag &= ~ICANON;
01854   if (!(flags & (0000002|0000040)))
01855         termios.c_lflag |= ICANON;
01856 
01857   /* IEXTEN     - set if not RAW */
01858   /* ISIG       - set if not RAW */
01859   termios.c_lflag &= ~(IEXTEN|ISIG);
01860   if (!(flags & 0000040))
01861         termios.c_lflag |= (IEXTEN|ISIG);
01862 
01863   /* NOFLSH     - not changed */
01864   /* TOSTOP     - not changed */
01865 
01866   tp->tty_termios = termios;
01867   setattr(tp);
01868   return(OK);
01869 }
01870 
01871 /*===========================================================================*
01872  *                              compat_setc                                  *
01873  *===========================================================================*/
01874 PRIVATE int compat_setc(tp, tc)
01875 tty_t *tp;
01876 struct tchars *tc;
01877 {
01878 /* Translate an old TIOCSETC to the termios equivalent. */
01879   struct termios termios;
01880 
01881   termios = tp->tty_termios;
01882 
01883   termios.c_cc[VINTR] = tc->t_intrc;
01884   termios.c_cc[VQUIT] = tc->t_quitc;
01885   termios.c_cc[VSTART] = tc->t_startc;
01886   termios.c_cc[VSTOP] = tc->t_stopc;
01887   termios.c_cc[VEOL] = tc->t_brkc;
01888   termios.c_cc[VEOF] = tc->t_eofc;
01889 
01890   tp->tty_termios = termios;
01891   setattr(tp);
01892   return(OK);
01893 }
01894 
01895 /* Table of termios line speed to sgtty line speed translations.   All termios
01896  * speeds are present even if sgtty didn't know about them.  (Now it does.)
01897  */
01898 PRIVATE struct s2s {
01899   speed_t       tspd;
01900   u8_t          sgspd;
01901 } ts2sgs[] = {
01902   { B0,           0 },
01903   { B50,         50 },
01904   { B75,         75 },
01905   { B110,         1 },
01906   { B134,       134 },
01907   { B200,         2 },
01908   { B300,         3 },
01909   { B600,         6 },
01910   { B1200,       12 },
01911   { B1800,       18 },
01912   { B2400,       24 },
01913   { B4800,       48 },
01914   { B9600,       96 },
01915   { B19200,     192 },
01916   { B38400,     195 },
01917   { B57600,     194 },
01918   { B115200,    193 },
01919 };
01920 
01921 /*===========================================================================*
01922  *                              tspd2sgspd                                   *
01923  *===========================================================================*/
01924 PRIVATE int tspd2sgspd(tspd)
01925 speed_t tspd;
01926 {
01927 /* Translate a termios speed to sgtty speed. */
01928   struct s2s *s;
01929 
01930   for (s = ts2sgs; s < ts2sgs + sizeof(ts2sgs)/sizeof(ts2sgs[0]); s++) {
01931         if (s->tspd == tspd) return(s->sgspd);
01932   }
01933   return 96;
01934 }
01935 
01936 /*===========================================================================*
01937  *                              sgspd2tspd                                   *
01938  *===========================================================================*/
01939 PRIVATE speed_t sgspd2tspd(sgspd)
01940 int sgspd;
01941 {
01942 /* Translate a sgtty speed to termios speed. */
01943   struct s2s *s;
01944 
01945   for (s = ts2sgs; s < ts2sgs + sizeof(ts2sgs)/sizeof(ts2sgs[0]); s++) {
01946         if (s->sgspd == sgspd) return(s->tspd);
01947   }
01948   return B9600;
01949 }
01950 
01951 #if ENABLE_BINCOMPAT
01952 /*===========================================================================*
01953  *                              do_ioctl_compat                              *
01954  *===========================================================================*/
01955 PRIVATE void do_ioctl_compat(tp, m_ptr)
01956 tty_t *tp;
01957 message *m_ptr;
01958 {
01959 /* Handle the old sgtty ioctl's that packed the sgtty or tchars struct into
01960  * the Minix message.  Efficient then, troublesome now.
01961  */
01962   int minor, proc, func, result, r;
01963   long flags, erki, spek;
01964   u8_t erase, kill, intr, quit, xon, xoff, brk, eof, ispeed, ospeed;
01965   struct sgttyb sg;
01966   struct tchars tc;
01967   message reply_mess;
01968 
01969   minor = m_ptr->TTY_LINE;
01970   proc = m_ptr->IO_ENDPT;
01971   func = m_ptr->REQUEST;
01972   spek = m_ptr->m2_l1;
01973   flags = m_ptr->m2_l2;
01974 
01975   switch(func)
01976   {
01977     case (('t'<<8) | 8):        /* TIOCGETP */
01978         r = compat_getp(tp, &sg);
01979         erase = sg.sg_erase;
01980         kill = sg.sg_kill;
01981         ispeed = sg.sg_ispeed;
01982         ospeed = sg.sg_ospeed;
01983         flags = sg.sg_flags;
01984         erki = ((long)ospeed<<24) | ((long)ispeed<<16) | ((long)erase<<8) |kill;
01985         break;
01986     case (('t'<<8) | 18):       /* TIOCGETC */
01987         r = compat_getc(tp, &tc);
01988         intr = tc.t_intrc;
01989         quit = tc.t_quitc;
01990         xon = tc.t_startc;
01991         xoff = tc.t_stopc;
01992         brk = tc.t_brkc;
01993         eof = tc.t_eofc;
01994         erki = ((long)intr<<24) | ((long)quit<<16) | ((long)xon<<8) | xoff;
01995         flags = (eof << 8) | brk;
01996         break;
01997     case (('t'<<8) | 17):       /* TIOCSETC */
01998         tc.t_stopc = (spek >> 0) & 0xFF;
01999         tc.t_startc = (spek >> 8) & 0xFF;
02000         tc.t_quitc = (spek >> 16) & 0xFF;
02001         tc.t_intrc = (spek >> 24) & 0xFF;
02002         tc.t_brkc = (flags >> 0) & 0xFF;
02003         tc.t_eofc = (flags >> 8) & 0xFF;
02004         r = compat_setc(tp, &tc);
02005         break;
02006     case (('t'<<8) | 9):        /* TIOCSETP */
02007         sg.sg_erase = (spek >> 8) & 0xFF;
02008         sg.sg_kill = (spek >> 0) & 0xFF;
02009         sg.sg_ispeed = (spek >> 16) & 0xFF;
02010         sg.sg_ospeed = (spek >> 24) & 0xFF;
02011         sg.sg_flags = flags;
02012         r = compat_setp(tp, &sg);
02013         break;
02014     default:
02015         r = ENOTTY;
02016   }
02017   reply_mess.m_type = TASK_REPLY;
02018   reply_mess.REP_ENDPT = m_ptr->IO_ENDPT;
02019   reply_mess.REP_STATUS = r;
02020   reply_mess.m2_l1 = erki;
02021   reply_mess.m2_l2 = flags;
02022   send(m_ptr->m_source, &reply_mess);
02023 }
02024 #endif /* ENABLE_BINCOMPAT */
02025 #endif /* ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT */
02026 

Generated on Fri Apr 14 22:56:56 2006 for minix by  doxygen 1.4.6