home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / sys / dev / tty.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-02-03  |  12.9 KB  |  729 lines

  1. #
  2. /*
  3.  * general TTY subroutines
  4.  */
  5. #include "../h/param.h"
  6. #include "../h/systm.h"
  7. #include "../h/dir.h"
  8. #include "../h/user.h"
  9. #include "../h/tty.h"
  10. #include "../h/proc.h"
  11. #include "../h/mx.h"
  12. #include "../h/inode.h"
  13. #include "../h/file.h"
  14. #include "../h/reg.h"
  15. #include "../h/conf.h"
  16.  
  17. char    partab[];
  18.  
  19.  
  20. /*
  21.  * Input mapping table-- if an entry is non-zero, when the
  22.  * corresponding character is typed preceded by "\" the escape
  23.  * sequence is replaced by the table value.  Mostly used for
  24.  * upper-case only terminals.
  25.  */
  26.  
  27. char    maptab[] ={
  28.     000,000,000,000,000,000,000,000,
  29.     000,000,000,000,000,000,000,000,
  30.     000,000,000,000,000,000,000,000,
  31.     000,000,000,000,000,000,000,000,
  32.     000,'|',000,000,000,000,000,'`',
  33.     '{','}',000,000,000,000,000,000,
  34.     000,000,000,000,000,000,000,000,
  35.     000,000,000,000,000,000,000,000,
  36.     000,000,000,000,000,000,000,000,
  37.     000,000,000,000,000,000,000,000,
  38.     000,000,000,000,000,000,000,000,
  39.     000,000,000,000,000,000,'~',000,
  40.     000,'A','B','C','D','E','F','G',
  41.     'H','I','J','K','L','M','N','O',
  42.     'P','Q','R','S','T','U','V','W',
  43.     'X','Y','Z',000,000,000,000,000,
  44. };
  45.  
  46.  
  47. /*
  48.  * shorthand
  49.  */
  50. #define    q1    tp->t_rawq
  51. #define    q2    tp->t_canq
  52. #define    q3    tp->t_outq
  53. #define    q4    tp->t_un.t_ctlq
  54.  
  55.  
  56. /*
  57.  * routine called on first teletype open.
  58.  * establishes a process group for distribution
  59.  * of quits and interrupts from the tty.
  60.  */
  61. ttyopen(dev, tp)
  62. dev_t dev;
  63. register struct tty *tp;
  64. {
  65.     register struct proc *pp;
  66.  
  67.     pp = u.u_procp;
  68.     tp->t_dev = dev;
  69.     if(pp->p_pgrp == 0) {
  70.         u.u_ttyp = tp;
  71.         u.u_ttyd = dev;
  72.         if (tp->t_pgrp==0)
  73.             tp->t_pgrp = pp->p_pid;
  74.         pp->p_pgrp = tp->t_pgrp;
  75.     }
  76.     tp->t_state &= ~WOPEN;
  77.     tp->t_state |= ISOPEN;
  78. }
  79.  
  80.  
  81. /*
  82.  * set default control characters.
  83.  */
  84. ttychars(tp)
  85. register struct tty *tp;
  86. {
  87.     tun.t_intrc = CINTR;
  88.     tun.t_quitc = CQUIT;
  89.     tun.t_startc = CSTART;
  90.     tun.t_stopc = CSTOP;
  91.     tun.t_eofc = CEOT;
  92.     tun.t_brkc = CBRK;
  93.     tp->t_erase = CERASE;
  94.     tp->t_kill = CKILL;
  95. }
  96.  
  97. /*
  98.  * clean tp on last close
  99.  */
  100. ttyclose(tp)
  101. register struct tty *tp;
  102. {
  103.  
  104.     tp->t_pgrp = 0;
  105.     wflushtty(tp);
  106.     tp->t_state = 0;
  107. }
  108.  
  109. /*
  110.  * stty/gtty writearound
  111.  */
  112. stty()
  113. {
  114.     u.u_arg[2] = u.u_arg[1];
  115.     u.u_arg[1] = TIOCSETP;
  116.     ioctl();
  117. }
  118.  
  119. gtty()
  120. {
  121.     u.u_arg[2] = u.u_arg[1];
  122.     u.u_arg[1] = TIOCGETP;
  123.     ioctl();
  124. }
  125.  
  126. /*
  127.  * ioctl system call
  128.  * Check legality, execute common code, and switch out to individual
  129.  * device routine.
  130.  */
  131. ioctl()
  132. {
  133.     register struct file *fp;
  134.     register struct inode *ip;
  135.     register struct a {
  136.         int    fdes;
  137.         int    cmd;
  138.         caddr_t    cmarg;
  139.     } *uap;
  140.     register dev_t dev;
  141.     register fmt;
  142.  
  143.     uap = (struct a *)u.u_ap;
  144.     if ((fp = getf(uap->fdes)) == NULL)
  145.         return;
  146.     if (uap->cmd==FIOCLEX) {
  147.         u.u_pofile[uap->fdes] |= EXCLOSE;
  148.         return;
  149.     }
  150.     if (uap->cmd==FIONCLEX) {
  151.         u.u_pofile[uap->fdes] &= ~EXCLOSE;
  152.         return;
  153.     }
  154.     ip = fp->f_inode;
  155.     fmt = ip->i_mode & IFMT;
  156.     if (fmt != IFCHR && fmt != IFMPC) {
  157.         u.u_error = ENOTTY;
  158.         return;
  159.     }
  160.     dev = (dev_t)ip->i_un.i_rdev;
  161.     (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
  162. }
  163.  
  164. /*
  165.  * Common code for several tty ioctl commands
  166.  */
  167. ttioccomm(com, tp, addr, dev)
  168. register struct tty *tp;
  169. caddr_t addr;
  170. {
  171.     unsigned t;
  172.     struct ttiocb iocb;
  173.     extern int nldisp;
  174.  
  175.     switch(com) {
  176.  
  177.     /*
  178.      * get discipline number
  179.      */
  180.     case TIOCGETD:
  181.         t = tp->t_line;
  182.         if (copyout((caddr_t)&t, addr, sizeof(t)))
  183.             u.u_error = EFAULT;
  184.         break;
  185.  
  186.     /*
  187.      * set line discipline
  188.      */
  189.     case TIOCSETD:
  190.         if (copyin(addr, (caddr_t)&t, sizeof(t))) {
  191.             u.u_error = EFAULT;
  192.             break;
  193.         }
  194.         if (t >= nldisp) {
  195.             u.u_error = ENXIO;
  196.             break;
  197.         }
  198.         if (tp->t_line)
  199.             (*linesw[tp->t_line].l_close)(tp);
  200.         if (t)
  201.             (*linesw[t].l_open)(dev, tp, addr);
  202.         if (u.u_error==0)
  203.             tp->t_line = t;
  204.         break;
  205.  
  206.     /*
  207.      * prevent more opens on channel
  208.      */
  209.     case TIOCEXCL:
  210.         tp->t_state |= XCLUDE;
  211.         break;
  212.     case TIOCNXCL:
  213.         tp->t_state &= ~XCLUDE;
  214.         break;
  215.  
  216.     /*
  217.      * Set new parameters
  218.      */
  219.     case TIOCSETP:
  220.         wflushtty(tp);
  221.     case TIOCSETN:
  222.         if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
  223.             u.u_error = EFAULT;
  224.             return(1);
  225.         }
  226.         tp->t_ispeed = iocb.ioc_ispeed;
  227.         tp->t_ospeed = iocb.ioc_ospeed;
  228.         tp->t_erase = iocb.ioc_erase;
  229.         tp->t_kill = iocb.ioc_kill;
  230.         tp->t_flags = iocb.ioc_flags;
  231.         break;
  232.  
  233.     /*
  234.      * send current parameters to user
  235.      */
  236.     case TIOCGETP:
  237.         iocb.ioc_ispeed = tp->t_ispeed;
  238.         iocb.ioc_ospeed = tp->t_ospeed;
  239.         iocb.ioc_erase = tp->t_erase;
  240.         iocb.ioc_kill = tp->t_kill;
  241.         iocb.ioc_flags = tp->t_flags;
  242.         if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
  243.             u.u_error = EFAULT;
  244.         break;
  245.  
  246.     /*
  247.      * Hang up line on last close
  248.      */
  249.  
  250.     case TIOCHPCL:
  251.         tp->t_state |= HUPCLS;
  252.         break;
  253.  
  254.     case TIOCFLUSH:
  255.         flushtty(tp);
  256.         break;
  257.  
  258.     /*
  259.      * ioctl entries to line discipline
  260.      */
  261.     case DIOCSETP:
  262.     case DIOCGETP:
  263.         (*linesw[tp->t_line].l_ioctl)(com, tp, addr);
  264.         break;
  265.  
  266.     /*
  267.      * set and fetch special characters
  268.      */
  269.     case TIOCSETC:
  270.         if (copyin(addr, (caddr_t)&tun, sizeof(struct tc)))
  271.             u.u_error = EFAULT;
  272.         break;
  273.  
  274.     case TIOCGETC:
  275.         if (copyout((caddr_t)&tun, addr, sizeof(struct tc)))
  276.             u.u_error = EFAULT;
  277.         break;
  278.  
  279.     default:
  280.         return(0);
  281.     }
  282.     return(1);
  283. }
  284.  
  285. /*
  286.  * Wait for output to drain, then flush input waiting.
  287.  */
  288. wflushtty(tp)
  289. register struct tty *tp;
  290. {
  291.  
  292.     spl5();
  293.     while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
  294.         (*tp->t_oproc)(tp);
  295.         tp->t_state |= ASLEEP;
  296.         sleep((caddr_t)&tp->t_outq, TTOPRI);
  297.     }
  298.     flushtty(tp);
  299.     spl0();
  300. }
  301.  
  302. /*
  303.  * flush all TTY queues
  304.  */
  305. flushtty(tp)
  306. register struct tty *tp;
  307. {
  308.     register s;
  309.  
  310.     while (getc(&tp->t_canq) >= 0)
  311.         ;
  312.     wakeup((caddr_t)&tp->t_rawq);
  313.     wakeup((caddr_t)&tp->t_outq);
  314.     s = spl6();
  315.     tp->t_state &= ~TTSTOP;
  316.     (*cdevsw[major(tp->t_dev)].d_stop)(tp);
  317.     while (getc(&tp->t_outq) >= 0)
  318.         ;
  319.     while (getc(&tp->t_rawq) >= 0)
  320.         ;
  321.     tp->t_delct = 0;
  322.     splx(s);
  323. }
  324.  
  325.  
  326.  
  327. /*
  328.  * transfer raw input list to canonical list,
  329.  * doing erase-kill processing and handling escapes.
  330.  * It waits until a full line has been typed in cooked mode,
  331.  * or until any character has been typed in raw mode.
  332.  */
  333. canon(tp)
  334. register struct tty *tp;
  335. {
  336.     register char *bp;
  337.     char *bp1;
  338.     register int c;
  339.     int mc;
  340.  
  341.     spl5();
  342.     while ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
  343.         || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
  344.         if ((tp->t_state&CARR_ON)==0 || tp->t_chan!=NULL) {
  345.             return(0);
  346.         }
  347.         sleep((caddr_t)&tp->t_rawq, TTIPRI);
  348.     }
  349.     spl0();
  350. loop:
  351.     bp = &canonb[2];
  352.     while ((c=getc(&tp->t_rawq)) >= 0) {
  353.         if ((tp->t_flags&(RAW|CBREAK))==0) {
  354.             if (c==0377) {
  355.                 tp->t_delct--;
  356.                 break;
  357.             }
  358.             if (bp[-1]!='\\') {
  359.                 if (c==tp->t_erase) {
  360.                     if (bp > &canonb[2])
  361.                         bp--;
  362.                     continue;
  363.                 }
  364.                 if (c==tp->t_kill)
  365.                     goto loop;
  366.                 if (c==tun.t_eofc)
  367.                     continue;
  368.             } else {
  369.                 mc = maptab[c];
  370.                 if (c==tp->t_erase || c==tp->t_kill)
  371.                     mc = c;
  372.                 if (mc && (mc==c || (tp->t_flags&LCASE))) {
  373.                     if (bp[-2] != '\\')
  374.                         c = mc;
  375.                     bp--;
  376.                 }
  377.             }
  378.         }
  379.         *bp++ = c;
  380.         if (bp>=canonb+CANBSIZ)
  381.             break;
  382.     }
  383.     bp1 = &canonb[2];
  384.     b_to_q(bp1, bp-bp1, &tp->t_canq);
  385.  
  386.     if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
  387.         if (putc(tun.t_startc, &tp->t_outq)==0) {
  388.             tp->t_state &= ~TBLOCK;
  389.             ttstart(tp);
  390.         }
  391.         tp->t_char = 0;
  392.     }
  393.  
  394.     return(bp-bp1);
  395. }
  396.  
  397.  
  398. /*
  399.  * block transfer input handler.
  400.  */
  401. ttyrend(tp, pb, pe)
  402. register struct tty *tp;
  403. register char *pb, *pe;
  404. {
  405.     int    tandem;
  406.  
  407.     tandem = tp->t_flags&TANDEM;
  408.     if (tp->t_flags&RAW) {
  409.         b_to_q(pb, pe-pb, &tp->t_rawq);
  410.         if (tp->t_chan)
  411.             sdata(tp->t_chan); else
  412.             wakeup((caddr_t)&tp->t_rawq);
  413.     } else {
  414.         tp->t_flags &= ~TANDEM;
  415.         while (pb < pe)
  416.             ttyinput(*pb++, tp);
  417.         tp->t_flags |= tandem;
  418.     }
  419.     if (tandem)
  420.         ttyblock(tp);
  421. }
  422.  
  423. /*
  424.  * Place a character on raw TTY input queue, putting in delimiters
  425.  * and waking up top half as needed.
  426.  * Also echo if required.
  427.  * The arguments are the character and the appropriate
  428.  * tty structure.
  429.  */
  430. ttyinput(c, tp)
  431. register c;
  432. register struct tty *tp;
  433. {
  434.     register int t_flags;
  435.     register struct chan *cp;
  436.  
  437.     tk_nin += 1;
  438.     c &= 0377;
  439.     t_flags = tp->t_flags;
  440.     if (t_flags&TANDEM)
  441.         ttyblock(tp);
  442.     if ((t_flags&RAW)==0) {
  443.         c &= 0177;
  444.         if (tp->t_state&TTSTOP) {
  445.             if (c==tun.t_startc) {
  446.                 tp->t_state &= ~TTSTOP;
  447.                 ttstart(tp);
  448.                 return;
  449.             }
  450.             if (c==tun.t_stopc)
  451.                 return;
  452.             tp->t_state &= ~TTSTOP;
  453.             ttstart(tp);
  454.         } else {
  455.             if (c==tun.t_stopc) {
  456.                 tp->t_state |= TTSTOP;
  457.                 (*cdevsw[major(tp->t_dev)].d_stop)(tp);
  458.                 return;
  459.             }
  460.             if (c==tun.t_startc)
  461.                 return;
  462.         }
  463.         if (c==tun.t_quitc || c==tun.t_intrc) {
  464.             flushtty(tp);
  465.             c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
  466.             if (tp->t_chan)
  467.                 scontrol(tp->t_chan, M_SIG, c);
  468.             else
  469.                 signal(tp->t_pgrp, c);
  470.             return;
  471.         }
  472.         if (c=='\r' && t_flags&CRMOD)
  473.             c = '\n';
  474.     }
  475.     if (tp->t_rawq.c_cc>TTYHOG) {
  476.         flushtty(tp);
  477.         return;
  478.     }
  479.     if (t_flags&LCASE && c>='A' && c<='Z')
  480.         c += 'a'-'A';
  481.     putc(c, &tp->t_rawq);
  482.     if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
  483.         if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
  484.             tp->t_delct++;
  485.         if ((cp=tp->t_chan)!=NULL)
  486.             sdata(cp); else
  487.             wakeup((caddr_t)&tp->t_rawq);
  488.     }
  489.     if (t_flags&ECHO) {
  490.         ttyoutput(c, tp);
  491.         if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
  492.             ttyoutput('\n', tp);
  493.         ttstart(tp);
  494.     }
  495. }
  496.  
  497.  
  498. /*
  499.  * Send stop character on input overflow.
  500.  */
  501. ttyblock(tp)
  502. register struct tty *tp;
  503. {
  504. register x;
  505.     x = q1.c_cc + q2.c_cc;
  506.     if (q1.c_cc > TTYHOG) {
  507.         flushtty(tp);
  508.         tp->t_state &= ~TBLOCK;
  509.     }
  510.     if (x >= TTYHOG/2) {
  511.         if (putc(tun.t_stopc, &tp->t_outq)==0) {
  512.             tp->t_state |= TBLOCK;
  513.             tp->t_char++;
  514.             ttstart(tp);
  515.         }
  516.     }
  517. }
  518.  
  519. /*
  520.  * put character on TTY output queue, adding delays,
  521.  * expanding tabs, and handling the CR/NL bit.
  522.  * It is called both from the top half for output, and from
  523.  * interrupt level for echoing.
  524.  * The arguments are the character and the tty structure.
  525.  */
  526. ttyoutput(c, tp)
  527. register c;
  528. register struct tty *tp;
  529. {
  530.     register char *colp;
  531.     register ctype;
  532.  
  533.     tk_nout += 1;
  534.     /*
  535.      * Ignore EOT in normal mode to avoid hanging up
  536.      * certain terminals.
  537.      * In raw mode dump the char unchanged.
  538.      */
  539.  
  540.     if ((tp->t_flags&RAW)==0) {
  541.         c &= 0177;
  542.         if (c==CEOT)
  543.             return;
  544.     } else {
  545.         putc(c, &tp->t_outq);
  546.         return;
  547.     }
  548.  
  549.     /*
  550.      * Turn tabs to spaces as required
  551.      */
  552.     if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
  553.         c = 8;
  554.         do
  555.             ttyoutput(' ', tp);
  556.         while (--c >= 0 && tp->t_col&07);
  557.         return;
  558.     }
  559.     /*
  560.      * for upper-case-only terminals,
  561.      * generate escapes.
  562.      */
  563.     if (tp->t_flags&LCASE) {
  564.         colp = "({)}!|^~'`";
  565.         while(*colp++)
  566.             if(c == *colp++) {
  567.                 ttyoutput('\\', tp);
  568.                 c = colp[-2];
  569.                 break;
  570.             }
  571.         if ('a'<=c && c<='z')
  572.             c += 'A' - 'a';
  573.     }
  574.     /*
  575.      * turn <nl> to <cr><lf> if desired.
  576.      */
  577.     if (c=='\n' && tp->t_flags&CRMOD)
  578.         ttyoutput('\r', tp);
  579.     putc(c, &tp->t_outq);
  580.     /*
  581.      * Calculate delays.
  582.      * The numbers here represent clock ticks
  583.      * and are not necessarily optimal for all terminals.
  584.      * The delays are indicated by characters above 0200.
  585.      * In raw mode there are no delays and the
  586.      * transmission path is 8 bits wide.
  587.      */
  588.     colp = &tp->t_col;
  589.     ctype = partab[c];
  590.     c = 0;
  591.     switch (ctype&077) {
  592.  
  593.     /* ordinary */
  594.     case 0:
  595.         (*colp)++;
  596.  
  597.     /* non-printing */
  598.     case 1:
  599.         break;
  600.  
  601.     /* backspace */
  602.     case 2:
  603.         if (*colp)
  604.             (*colp)--;
  605.         break;
  606.  
  607.     /* newline */
  608.     case 3:
  609.         ctype = (tp->t_flags >> 8) & 03;
  610.         if(ctype == 1) { /* tty 37 */
  611.             if (*colp)
  612.                 c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
  613.         } else
  614.         if(ctype == 2) { /* vt05 */
  615.             c = 6;
  616.         }
  617.         *colp = 0;
  618.         break;
  619.  
  620.     /* tab */
  621.     case 4:
  622.         ctype = (tp->t_flags >> 10) & 03;
  623.         if(ctype == 1) { /* tty 37 */
  624.             c = 1 - (*colp | ~07);
  625.             if(c < 5)
  626.                 c = 0;
  627.         }
  628.         *colp |= 07;
  629.         (*colp)++;
  630.         break;
  631.  
  632.     /* vertical motion */
  633.     case 5:
  634.         if(tp->t_flags & VTDELAY) /* tty 37 */
  635.             c = 0177;
  636.         break;
  637.  
  638.     /* carriage return */
  639.     case 6:
  640.         ctype = (tp->t_flags >> 12) & 03;
  641.         if(ctype == 1) { /* tn 300 */
  642.             c = 5;
  643.         } else if(ctype == 2) { /* ti 700 */
  644.             c = 10;
  645.         }
  646.         *colp = 0;
  647.     }
  648.     if(c)
  649.         putc(c|0200, &tp->t_outq);
  650. }
  651.  
  652. /*
  653.  * Restart typewriter output following a delay
  654.  * timeout.
  655.  * The name of the routine is passed to the timeout
  656.  * subroutine and it is called during a clock interrupt.
  657.  */
  658. ttrstrt(tp)
  659. register struct tty *tp;
  660. {
  661.  
  662.     tp->t_state &= ~TIMEOUT;
  663.     ttstart(tp);
  664. }
  665.  
  666. /*
  667.  * Start output on the typewriter. It is used from the top half
  668.  * after some characters have been put on the output queue,
  669.  * from the interrupt routine to transmit the next
  670.  * character, and after a timeout has finished.
  671.  */
  672. ttstart(tp)
  673. register struct tty *tp;
  674. {
  675.     register s;
  676.  
  677.     s = spl5();
  678.     if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
  679.         (*tp->t_oproc)(tp);
  680.     splx(s);
  681. }
  682.  
  683. /*
  684.  * Called from device's read routine after it has
  685.  * calculated the tty-structure given as argument.
  686.  */
  687. ttread(tp)
  688. register struct tty *tp;
  689. {
  690.  
  691.     if ((tp->t_state&CARR_ON)==0)
  692.         return(0);
  693.     if (tp->t_canq.c_cc || canon(tp))
  694.         while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
  695.             ;
  696.     return(tp->t_rawq.c_cc + tp->t_canq.c_cc);
  697. }
  698.  
  699. /*
  700.  * Called from the device's write routine after it has
  701.  * calculated the tty-structure given as argument.
  702.  */
  703. caddr_t
  704. ttwrite(tp)
  705. register struct tty *tp;
  706. {
  707.     register c;
  708.  
  709.     if ((tp->t_state&CARR_ON)==0)
  710.         return(NULL);
  711.     while (u.u_count) {
  712.         spl5();
  713.         while (tp->t_outq.c_cc > TTHIWAT) {
  714.             ttstart(tp);
  715.             tp->t_state |= ASLEEP;
  716.             if (tp->t_chan) 
  717.                 return((caddr_t)&tp->t_outq);
  718.             sleep((caddr_t)&tp->t_outq, TTOPRI);
  719.         }
  720.         spl0();
  721.         if ((c = cpass()) < 0)
  722.             break;
  723.         ttyoutput(c, tp);
  724.     }
  725.     ttstart(tp);
  726.     return(NULL);
  727. }
  728.  
  729.