home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xntp3.zip / kernel / tty_clk.c < prev   
C/C++ Source or Header  |  1992-06-08  |  7KB  |  304 lines

  1. /*
  2.  * tty_clk.c - Generic line driver for receiving radio clock timecodes
  3.  */
  4.  
  5. #include "clk.h"
  6. #if NCLK > 0
  7.  
  8. #include "../h/param.h"
  9. #include "../h/types.h"
  10. #include "../h/systm.h"
  11. #include "../h/dir.h"
  12. #include "../h/user.h"
  13. #include "../h/ioctl.h"
  14. #include "../h/tty.h"
  15. #include "../h/proc.h"
  16. #include "../h/file.h"
  17. #include "../h/conf.h"
  18. #include "../h/buf.h"
  19. #include "../h/uio.h"
  20. #include "../h/clist.h"
  21.  
  22. /*
  23.  * This line discipline is intended to provide well performing
  24.  * generic support for the reception and time stamping of radio clock
  25.  * timecodes.  Most radio clock devices return a string where a
  26.  * particular character in the code (usually a \r) is on-time
  27.  * synchronized with the clock.  The idea here is to collect characters
  28.  * until (one of) the synchronization character(s) (we allow two) is seen.
  29.  * When the magic character arrives we take a timestamp by calling
  30.  * microtime() and insert the eight bytes of struct timeval into the
  31.  * buffer after the magic character.  We then wake up anyone waiting
  32.  * for the buffer and return the whole mess on the next read.
  33.  *
  34.  * To use this the calling program is expected to first open the
  35.  * port, and then to set the port into raw mode with the speed
  36.  * set appropriately with a TIOCSETP ioctl(), with the erase and kill
  37.  * characters set to those to be considered magic (yes, I know this
  38.  * is gross, but they were so convenient).  If only one character is
  39.  * magic you can set then both the same, or perhaps to the alternate
  40.  * parity versions of said character.  After getting all this set,
  41.  * change the line discipline to CLKLDISC and you are on your way.
  42.  *
  43.  * The only other bit of magic we do in here is to flush the receive
  44.  * buffers on writes if the CRMOD flag is set (hack, hack).
  45.  */
  46.  
  47. /*
  48.  * We run this very much like a raw mode terminal, with the exception
  49.  * that we store up characters locally until we hit one of the
  50.  * magic ones and then dump it into the rawq all at once.  We keep
  51.  * the buffered data in clists since we can then often move it to
  52.  * the rawq without copying.  For sanity we limit the number of
  53.  * characters between specials, and the total number of characters
  54.  * before we flush the rawq, as follows.
  55.  */
  56. #define    CLKLINESIZE    (256)
  57. #define    NCLKCHARS    (CLKLINESIZE*4)
  58.  
  59. struct clkdata {
  60.     int inuse;
  61.     struct clist clkbuf;
  62. };
  63. #define    clk_cc    clkbuf.c_cc
  64. #define    clk_cf    clkbuf.c_cf
  65. #define    clk_cl    clkbuf.c_cl
  66.  
  67. struct clkdata clk_data[NCLK];
  68.  
  69. /*
  70.  * Routine for flushing the internal clist
  71.  */
  72. #define    clk_bflush(clk)        (ndflush(&((clk)->clkbuf), (clk)->clk_cc))
  73.  
  74. int clk_debug = 0;
  75.  
  76. /*ARGSUSED*/
  77. clkopen(dev, tp)
  78.     dev_t dev;
  79.     register struct tty *tp;
  80. {
  81.     register struct clkdata *clk;
  82.  
  83.     /*
  84.      * Don't allow multiple opens.  This will also protect us
  85.      * from someone opening /dev/tty
  86.      */
  87.     if (tp->t_line == CLKLDISC)
  88.         return (EBUSY);
  89.     ttywflush(tp);
  90.     for (clk = clk_data; clk < &clk_data[NCLK]; clk++)
  91.         if (!clk->inuse)
  92.             break;
  93.     if (clk >= &clk_data[NCLK])
  94.         return (EBUSY);
  95.     clk->inuse++;
  96.     clk->clk_cc = 0;
  97.     clk->clk_cf = clk->clk_cl = NULL;
  98.     tp->T_LINEP = (caddr_t) clk;
  99.     return (0);
  100. }
  101.  
  102.  
  103. /*
  104.  * Break down... called when discipline changed or from device
  105.  * close routine.
  106.  */
  107. clkclose(tp)
  108.     register struct tty *tp;
  109. {
  110.     register struct clkdata *clk;
  111.     register int s = spltty();
  112.  
  113.     clk = (struct clkdata *)tp->T_LINEP;
  114.     if (clk->clk_cc > 0)
  115.         clk_bflush(clk);
  116.     clk->inuse = 0;
  117.     tp->t_line = 0;            /* paranoid: avoid races */
  118.     splx(s);
  119. }
  120.  
  121.  
  122. /*
  123.  * Receive a write request.  We pass these requests on to the terminal
  124.  * driver, except that if the CRMOD bit is set in the flags we
  125.  * first flush the input queues.
  126.  */
  127. clkwrite(tp, uio)
  128.     register struct tty *tp;
  129.     struct uio *uio;
  130. {
  131.     if (tp->t_flags & CRMOD) {
  132.         register struct clkdata *clk;
  133.         int s;
  134.  
  135.         s = spltty();
  136.         if (tp->t_rawq.c_cc > 0)
  137.             ndflush(&tp->t_rawq, tp->t_rawq.c_cc);
  138.         clk = (struct clkdata *) tp->T_LINEP;
  139.         if (clk->clk_cc > 0)
  140.             clk_bflush(clk);
  141.         (void)splx(s);
  142.     }
  143.     ttwrite(tp, uio);
  144. }
  145.  
  146.  
  147. /*
  148.  * Low level character input routine.
  149.  * If the character looks okay, grab a time stamp.  If the stuff in
  150.  * the buffer is too old, dump it and start fresh.  If the character is
  151.  * non-BCDish, everything in the buffer too.
  152.  */
  153. clkinput(c, tp)
  154.     register int c;
  155.     register struct tty *tp;
  156. {
  157.     register struct clkdata *clk;
  158.     register int i;
  159.     register long s;
  160.     struct timeval tv;
  161.  
  162.     /*
  163.      * Check to see whether this isn't the magic character.  If not,
  164.      * save the character and return.
  165.      */
  166. #ifdef ultrix
  167.     if (c != tp->t_cc[VERASE] && c != tp->t_cc[VKILL]) {
  168. #else
  169.     if (c != tp->t_erase && c != tp->t_kill) {
  170. #endif
  171.         clk = (struct clkdata *) tp->T_LINEP;
  172.         if (clk->clk_cc >= CLKLINESIZE)
  173.             clk_bflush(clk);
  174.         if (putc(c, &clk->clkbuf) == -1) {
  175.             /*
  176.              * Hopeless, no clists.  Flush what we have
  177.              * and hope things improve.
  178.              */
  179.             clk_bflush(clk);
  180.         }
  181.         return;
  182.     }
  183.  
  184.     /*
  185.      * Here we have a magic character.  Get a timestamp and store
  186.      * everything.
  187.      */
  188.     microtime(&tv);
  189.     clk = (struct clkdata *) tp->T_LINEP;
  190.  
  191.     if (putc(c, &clk->clkbuf) == -1)
  192.         goto flushout;
  193.     
  194.     s = tv.tv_sec;
  195.     for (i = 0; i < sizeof(long); i++) {
  196.         if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
  197.             goto flushout;
  198.         s <<= 8;
  199.     }
  200.  
  201.     s = tv.tv_usec;
  202.     for (i = 0; i < sizeof(long); i++) {
  203.         if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
  204.             goto flushout;
  205.         s <<= 8;
  206.     }
  207.  
  208.     /*
  209.      * If the length of the rawq exceeds our sanity limit, dump
  210.      * all the old crap in there before copying this in.
  211.      */
  212.     if (tp->t_rawq.c_cc > NCLKCHARS)
  213.         ndflush(&tp->t_rawq, tp->t_rawq.c_cc);
  214.     
  215.     /*
  216.      * Now copy the buffer in.  There is a special case optimization
  217.      * here.  If there is nothing on the rawq at present we can
  218.      * just copy the clists we own over.  Otherwise we must concatenate
  219.      * the present data on the end.
  220.      */
  221.     s = (long)spltty();
  222.     if (tp->t_rawq.c_cc <= 0) {
  223.         tp->t_rawq = clk->clkbuf;
  224.         clk->clk_cc = 0;
  225.         clk->clk_cl = clk->clk_cf = NULL;
  226.         (void) splx((int)s);
  227.     } else {
  228.         (void) splx((int)s);
  229.         catq(&clk->clkbuf, &tp->t_rawq);
  230.         clk_bflush(clk);
  231.     }
  232.  
  233.     /*
  234.      * Tell the world
  235.      */
  236.     ttwakeup(tp);
  237.     return;
  238.  
  239. flushout:
  240.     /*
  241.      * It would be nice if this never happened.  Flush the
  242.      * internal clists and hope someone else frees some of them
  243.      */
  244.     clk_bflush(clk);
  245.     return;
  246. }
  247.  
  248.  
  249. /*
  250.  * Handle ioctls.  We reject most tty-style except those that
  251.  * change the line discipline and a couple of others..
  252.  */
  253. clkioctl(tp, cmd, data, flag)
  254.     struct tty *tp;
  255.     int cmd;
  256.     caddr_t data;
  257.     int flag;
  258. {
  259.     int flags;
  260.     struct sgttyb *sg;
  261.  
  262.     if ((cmd>>8) != 't')
  263.         return (-1);
  264.     switch (cmd) {
  265.     case TIOCSETD:
  266.     case TIOCGETD:
  267.     case TIOCGETP:
  268.     case TIOCGETC:
  269.     case TIOCOUTQ:
  270.         return (-1);
  271.  
  272.     case TIOCSETP:
  273.         /*
  274.          * He likely wants to set new magic characters in.
  275.          * Do this part.
  276.          */
  277.         sg = (struct sgttyb *)data;
  278. #ifdef ultrix
  279.         tp->t_cc[VERASE] = sg->sg_erase;
  280.         tp->t_cc[VKILL] = sg->sg_kill;
  281. #else
  282.         tp->t_erase = sg->sg_erase;
  283.         tp->t_kill = sg->sg_kill;
  284. #endif
  285.         return (0);
  286.  
  287.     case TIOCFLUSH:
  288.         flags = *(int *)data;
  289.         if (flags == 0 || (flags & FREAD)) {
  290.             register struct clkdata *clk;
  291.  
  292.             clk = (struct clkdata *) tp->T_LINEP;
  293.             if (clk->clk_cc > 0)
  294.                 clk_bflush(clk);
  295.         }
  296.         return (-1);
  297.     
  298.     default:
  299.         break;
  300.     }
  301.     return (ENOTTY);    /* not quite appropriate */
  302. }
  303. #endif NCLK
  304.