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