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 / dcf77sync.c < prev    next >
C/C++ Source or Header  |  1992-07-09  |  31KB  |  1,385 lines

  1. /*
  2.  * $Header: /src/NTP/v3/xntp/kernel/RCS/dcf77sync.c,v 2.8 1992/07/09 15:46:56 kardel XNTP-DCF-1 $
  3.  *  
  4.  * $Id: dcf77sync.c,v 2.8 1992/07/09 15:46:56 kardel XNTP-DCF-1 $
  5.  *
  6.  * STREAMS module for reference clock
  7.  * (SunOS4.x)
  8.  *
  9.  * Copyright (c) 1989,1990,1991,1992
  10.  * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg
  11.  *                                    
  12.  * This code can be modified and used freely provided that the
  13.  * credits remain intact.
  14.  * 
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  18.  *
  19.  * $Log: dcf77sync.c,v $
  20.  * Revision 2.8  1992/07/09  15:46:56  kardel
  21.  * fixed crash type bugs in RR strategy
  22.  * added format for ELV DCF7000
  23.  *
  24.  * Revision 2.7  1992/07/09  07:21:45  kardel
  25.  * comments and renaming to cvt_meinberg
  26.  *
  27.  * Revision 2.6  1992/07/08  11:41:17  kardel
  28.  * ifdef messup (VDDRV)
  29.  *
  30.  * Revision 2.5  1992/07/08  11:34:36  kardel
  31.  * RR search for conversion routines
  32.  * bad conversion statistics
  33.  *
  34.  * Revision 2.4  1992/07/06  13:58:40  kardel
  35.  * support for returning format code in DCFIOC_TIMECODE
  36.  *
  37.  * Revision 2.3  1992/07/06  10:03:57  kardel
  38.  * syncevt gets an additional parameter (local
  39.  * data structure)
  40.  *
  41.  * Revision 2.2  1992/07/05  22:14:09  kardel
  42.  * fixed memory allocation bug
  43.  *
  44.  * Revision 2.1  1992/07/05  21:31:40  kardel
  45.  * initial extendable multi protocol version
  46.  *
  47.  * Revision 1.7  1992/05/18  11:52:26  kardel
  48.  * using uniqtime for max precision (HIREZ timer on
  49.  * sun4c, SUN4_330, SUN4_470 - requires patch of
  50.  * badly compiled kern_clock.o - uniqtime routine)
  51.  *
  52.  * Revision 1.6  1992/03/13  16:46:17  kardel
  53.  * legal terms changed
  54.  *
  55.  * Revision 1.5  92/02/05  16:00:43  kardel
  56.  * renamed vddrv structure vd to dcf77sync_vd to avoid
  57.  * name clashed with commercial software
  58.  * 
  59.  * Revision 1.4  92/01/15  15:57:42  kardel
  60.  * changed operation default to
  61.  * "just time stamp sampling"
  62.  * 
  63.  * Revision 1.3  1991/12/16  12:52:25  kardel
  64.  * RCS version support for loadable driver
  65.  *
  66.  * Revision 1.2  1991/12/16  12:26:55  kardel
  67.  * RCS version support
  68.  *
  69.  * Revision 1.1  1991/12/16  10:58:23  kardel
  70.  * Initial revision
  71.  *
  72.  */
  73.  
  74. #ifndef lint
  75. static char rcsid[] = "$Id: dcf77sync.c,v 2.8 1992/07/09 15:46:56 kardel XNTP-DCF-1 $ FAU";
  76. #endif
  77.  
  78. #include "sys/types.h"
  79. #include "sys/conf.h"
  80. #include "sys/buf.h"
  81. #include "sys/param.h"
  82. #include "sys/sysmacros.h"
  83. #include "sys/errno.h"
  84. #include "sys/time.h"
  85. #include "sundev/mbvar.h"
  86. #include "sun/autoconf.h"
  87. #include "sys/stream.h"
  88. #include "sys/stropts.h"
  89. #include "sys/dir.h"
  90. #include "sys/signal.h"
  91. #include "sys/termios.h"
  92. #include "sys/termio.h"
  93. #include "sys/ttold.h"
  94. #include "sys/user.h"
  95. #include "sys/errno.h"
  96. #include "sys/tty.h"
  97. #ifdef VDDRV
  98. #include "sun/vddrv.h"
  99. #endif
  100.  
  101. #include "dcf77.h"
  102. #include "dcf77sync.h"
  103.  
  104. #ifdef VDDRV
  105. static unsigned int dcfbusy = 0;
  106.  
  107. /*--------------- loadable driver section -----------------------------*/
  108.  
  109. extern struct streamtab dcfinfo;
  110.  
  111. struct vdldrv dcf77sync_vd = 
  112. {
  113.   VDMAGIC_PSEUDO,        /* nothing like a real driver - a STREAMS module */
  114.   "DCF-77       ",        /* name this baby - keep room for revision number */
  115.   0,                /* no mb_ctlr structure */
  116.   0,                /* no md_driver structure */
  117.   0,                /* no mb_device structure */
  118.   0,                /* no controllers */
  119.   0,                /* no devices */
  120.   0,                /* no bdevsw entry */
  121.   0,                /* no cdevsw entry */
  122.   0,                /* choose any block number (don't you dare) */
  123.   0,                /* choose any character number (see above) */
  124. };
  125.  
  126. /*
  127.  * strings support usually not in kernel
  128.  */
  129. static int strlen(s)
  130.   register char *s;
  131. {
  132.   register int c;
  133.  
  134.   c = 0;
  135.   if (s)
  136.     {
  137.       while (*s++)
  138.     {
  139.       c++;
  140.     }
  141.     }
  142.   return c;
  143. }
  144.  
  145. static char *strncpy(t, s, c)
  146.   register char *t;
  147.   register char *s;
  148.   register int   c;
  149. {
  150.   register char *T = t;
  151.   
  152.   if (s && t)
  153.     {
  154.       while ((c-- > 0) && (*t++ = *s++))
  155.     ;
  156.     }
  157.   return T;
  158. }
  159.  
  160.  
  161. /*
  162.  * driver init routine
  163.  * since no mechanism gets us into and out of the fmodsw, we have to
  164.  * do it ourselves
  165.  */
  166. /*ARGSUSED*/
  167. int xxxinit(fc, vdp, vdi, vds)
  168.   unsigned int fc;
  169.   struct vddrv *vdp;
  170.   addr_t vdi;
  171.   struct vdstat *vds;
  172. {
  173.   extern struct fmodsw fmodsw[];
  174.   extern int fmodcnt;
  175.   
  176.   struct fmodsw *fm    = fmodsw;
  177.   struct fmodsw *fmend = &fmodsw[fmodcnt];
  178.   struct fmodsw *ifm   = (struct fmodsw *)0;
  179.   char *mname          = dcfinfo.st_rdinit->qi_minfo->mi_idname;
  180.   
  181.   switch (fc)
  182.     {
  183.     case VDLOAD:
  184.       vdp->vdd_vdtab = (struct vdlinkage *)&dcf77sync_vd;
  185.       /*
  186.        * now, jog fmodsw along scanning for an empty slot
  187.        * and deposit out name there
  188.        */
  189.       while (fm <= fmend)
  190.     {
  191.       if (!strncmp(fm->f_name, mname, FMNAMESZ))
  192.         {
  193.           printf("vddrinit[%s]: STREAMS module already loaded.\n", mname);
  194.           return(EBUSY);
  195.         }
  196.       else
  197.         if ((ifm == (struct fmodsw *)0) && 
  198.                 (fm->f_name[0] == '\0') && (fm->f_str == (struct streamtab *)0))
  199.           {
  200.         /*
  201.          * got one - so move in
  202.          */
  203.         ifm = fm;
  204.           }
  205.       fm++;
  206.     }
  207.       if (ifm == (struct fmodsw *)0)
  208.     {
  209.       printf("vddrinit[%s]: no slot free for STREAMS module\n", mname);
  210.       return (ENOSPC);
  211.     }
  212.       else
  213.         {
  214.       static char revision[] = "$Revision: 2.8 $";
  215.       char *s, *S, *t;
  216.       
  217.       strncpy(ifm->f_name, mname, FMNAMESZ);
  218.       ifm->f_name[FMNAMESZ] = '\0';
  219.       ifm->f_str = &dcfinfo;
  220.       /*
  221.        * copy RCS revision into Drv_name
  222.        *
  223.        * are we forcing RCS here to do things it was not built for ?
  224.        */
  225.       s = revision;
  226.       while (*s && (*s != ' '))
  227.         {
  228.           s++;
  229.         }
  230.       if (*s == ' ') s++;
  231.       
  232.       t = dcf77sync_vd.Drv_name; 
  233.       while (*t && (*t != ' '))
  234.         {
  235.           t++;
  236.         }
  237.       if (*t == ' ') t++;
  238.       
  239.       S = s;
  240.       while (*S && (((*S >= '0') && (*S <= '9')) || (*S == '.')))
  241.         {
  242.           S++;
  243.         }
  244.       
  245.       if (*s && *t && (S > s))
  246.         {
  247.           if (strlen(t) >= (S - s))
  248.         {
  249.           (void) strncpy(t, s, S - s);
  250.         }
  251.         }
  252.       return (0);
  253.         } 
  254.       break;
  255.       
  256.     case VDUNLOAD:
  257.       if (dcfbusy > 0)
  258.     {
  259.       return (EBUSY);
  260.     }
  261.       else
  262.     {
  263.       while (fm <= fmend)
  264.         {
  265.           if (!strncmp(fm->f_name, mname, FMNAMESZ))
  266.         {
  267.           /*
  268.            * got it - kill entry
  269.            */
  270.           fm->f_name[0] = '\0';
  271.           fm->f_str = (struct streamtab *)0;
  272.           fm++;
  273.           
  274.           break;
  275.         }
  276.           fm++;
  277.         }
  278.       if (fm > fmend)
  279.         {
  280.           printf("vddrinit[%s]: cannot find entry for STREAMS module\n", mname);
  281.           return (ENXIO);
  282.         }
  283.       else
  284.         return (0);
  285.     }
  286.       
  287.  
  288.     case VDSTAT:
  289.       return (0);
  290.  
  291.     default:
  292.       return (EIO);
  293.       
  294.     }
  295.   return EIO;
  296. }
  297.  
  298. #endif
  299. /*--------------- stream module definition ----------------------------*/
  300.  
  301. static int dcfopen(), dcfclose(), dcfwput(), dcfrput(), dcfrsvc();
  302.  
  303. static struct module_info driverinfo =
  304. {
  305.   0,                /* module ID number */
  306.   "dcf",            /* module name */
  307.   0,                /* minimum accepted packet size */
  308.   INFPSZ,            /* maximum accepted packet size */
  309.   1,                /* high water mark - flow control */
  310.   0                /* low water mark - flow control */
  311. };
  312.  
  313. static struct qinit rinit =    /* read queue definition */
  314. {
  315.   dcfrput,            /* put procedure */
  316.   dcfrsvc,            /* service procedure */
  317.   dcfopen,            /* open procedure */
  318.   dcfclose,            /* close procedure */
  319.   NULL,                /* admin procedure - NOT USED FOR NOW */
  320.   &driverinfo,            /* information structure */
  321.   NULL                /* statistics */
  322. };
  323.  
  324. static struct qinit winit =    /* write queue definition */
  325. {
  326.   dcfwput,            /* put procedure */
  327.   NULL,                /* service procedure */
  328.   NULL,                /* open procedure */
  329.   NULL,                /* close procedure */
  330.   NULL,                /* admin procedure - NOT USED FOR NOW */
  331.   &driverinfo,            /* information structure */
  332.   NULL                /* statistics */
  333. };
  334.  
  335. struct streamtab dcfinfo =    /* stream info element for dpr driver */
  336. {
  337.   &rinit,            /* read queue */
  338.   &winit,            /* write queue */
  339.   NULL,                /* read mux */
  340.   NULL,                /* write mux */
  341.   NULL                /* module auto push */
  342. };
  343.  
  344. /*--------------- driver data structures ----------------------------*/
  345.  
  346. int dcfdebug = ~0;
  347.  
  348. /*--------------- clock string parser data structures----------------*/
  349.  
  350.  
  351. extern void uniqtime();
  352. static void timepacket();
  353.  
  354. static int cvt_simple();
  355. static int cvt_dcf7000();
  356. static void syn_simple();
  357. /*
  358.  * The Meinberg receiver every second sends a datagram of the following form
  359.  * 
  360.  *     <STX>D:<dd>.<mm>.<yy>;T:<w>;U:<hh>:<mm>:<ss>;<S><F><D><A><ETX>
  361.  * pos:  0  00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2  2  3  3   3
  362.  *       1  23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8  9  0  1   2
  363.  * <SOT>           = '\002' ASCII start of text
  364.  * <EOT>           = '\003' ASCII end of text
  365.  * <dd>,<mm>,<yy>  = day, month, year(2 digits!!)
  366.  * <w>             = day of week (sunday= 0)
  367.  * <hh>,<mm>,<ss>  = hour, minute, second
  368.  * <S>             = '#' if never synced since powerup else ' ' for DCF U/A 31
  369.  *                   '#' if not PZF sychronisation available else ' ' for PZF 535
  370.  * <F>             = '*' if time comes from internal quartz else ' '
  371.  * <D>             = 'S' if daylight saving time is active else ' '
  372.  * <A>             = '!' during the hour preceeding an daylight saving time
  373.  *                       start/end change
  374.  */
  375.  
  376. /*
  377.  * field location structure (Meinberg clocks/simple format)
  378.  */
  379. #define O_DAY    0
  380. #define O_MONTH 1
  381. #define O_YEAR    2
  382. #define O_HOUR    3
  383. #define O_MIN    4
  384. #define    O_SEC    5
  385. #define O_WDAY    6
  386. #define O_FLAGS 7
  387. #define O_ZONE  8
  388. #define O_COUNT (O_ZONE+1)
  389.  
  390. #define MBG_EXTENDED    0x00000001
  391.  
  392. static struct format
  393. {
  394.   struct foff
  395.     {
  396.       char offset;        /* offset into buffer */
  397.       char length;        /* length of field */
  398.     } field_offsets[O_COUNT];
  399.   char *fixed_string;        /* string with must be chars (blanks = wildcards) */
  400.   unsigned long flags;
  401. } formats[] =
  402. {
  403.   {
  404.     {
  405.       { 3, 2}, { 6, 2}, { 9, 2}, { 18, 2}, { 21, 2}, { 24, 2}, { 14, 1}, { 27, 4}, { 29, 1 }
  406.       
  407.     },
  408.     "\2D:  .  .  ;T: ;U:  .  .  ;    \3",
  409.     0
  410.   },
  411.   {                /*
  412.                  * preliminary definition - will change
  413.                  * when actual format is known
  414.                  */
  415.     {
  416.       { 3, 2}, { 6, 2}, { 9, 2}, { 18, 2}, { 21, 2}, { 24, 2}, { 14, 1}, { 27, 4}, { 29, 1 }
  417.     },
  418.     "\2  .  .  ; ;  .  .  ;      \3",
  419.     MBG_EXTENDED
  420.   },
  421.   {                /* ELV DCF7000 */
  422.     {
  423.       { 6, 2}, { 3, 2}, { 0, 2}, { 12, 2}, { 15, 2}, { 18, 2}, { 9, 2}, { 21, 2}, { 0, 0 }
  424.     },
  425.     "  -  -  -  -  -  -  -  \r",
  426.     0
  427.   }
  428. };    
  429.  
  430. /*
  431.  * format definitions
  432.  */
  433. static clockformat_t clockformats[] =
  434. {
  435.   {
  436.     cvt_simple,
  437.     syn_simple,
  438.     (void *)&formats[0],
  439.     "Meinberg Standard",
  440.     32,
  441.     F_START|F_END|SYNC_END,
  442.     '\2',
  443.     '\3',
  444.     0
  445.   },
  446.   {
  447.     cvt_simple,
  448.     syn_simple,
  449.     (void *)&formats[1],
  450.     "Meinberg Extended",
  451.     32,
  452.     F_START|F_END|SYNC_END,
  453.     '\2',
  454.     '\3',
  455.     0
  456.   },
  457.   {
  458.     cvt_dcf7000,
  459.     syn_simple,
  460.     (void *)&formats[2],
  461.     "ELV DCF7000",
  462.     24,
  463.     F_END|SYNC_END,
  464.     '\0',
  465.     '\r',
  466.     0
  467.   }
  468. };
  469.  
  470. static nformats = sizeof(clockformats) / sizeof(clockformats[0]);
  471.  
  472. /*--------------- module implementation -----------------------------*/
  473.  
  474. /*ARGSUSED*/
  475. static int dcfopen(q, dev, flag, sflag)
  476.   queue_t *q;
  477.   dev_t dev;
  478.   int flag;
  479.   int sflag;
  480. {
  481.   register mblk_t *mp;
  482.   register dcf_t *dcf;
  483.   register int i;
  484.   register int f = 0;
  485.   
  486.   dcfprintf(DD_OPEN,("dcf77: OPEN\n")); 
  487.   
  488.   if (sflag != MODOPEN)
  489.     {            /* open only for modules */
  490.       dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - not MODOPEN\n")); 
  491.       return OPENFAIL;
  492.     }
  493.  
  494.   if (q->q_ptr != (caddr_t)NULL)
  495.     {
  496.       u.u_error = EBUSY;
  497.       dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - EXCLUSIVE ONLY\n")); 
  498.       return OPENFAIL;
  499.     }
  500.  
  501. #ifdef VDDRV
  502.   dcfbusy++;
  503. #endif
  504.   
  505.   q->q_ptr = (caddr_t)kmem_alloc(sizeof(dcf_t));
  506.   WR(q)->q_ptr = q->q_ptr;
  507.   
  508.   dcf = (dcf_t *) q->q_ptr;
  509.   bzero((caddr_t)dcf, sizeof(*dcf));
  510.   dcf->dcf_queue     = q;
  511.  
  512.   /*
  513.    * gather bitmaps of possible start and end values
  514.    */
  515.   for (i=0; i < nformats; i++)
  516.     {
  517.       if (clockformats[i].flags & F_START)
  518.     {
  519.       if (dcf->dcf_endsym[clockformats[i].startsym / 8] & (1 << (clockformats[i].startsym % 8)))
  520.         {
  521. #ifdef VDDRV
  522.           dcfbusy--;
  523. #endif
  524.           dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - START/END conflict\n")); 
  525.           return OPENFAIL;
  526.         }
  527.       else
  528.         {
  529.           dcf->dcf_startsym[clockformats[i].startsym / 8] |= (1 << (clockformats[i].startsym % 8));
  530.           f = 1;
  531.         }
  532.     }
  533.  
  534.       if (clockformats[i].flags & F_END)
  535.     {
  536.       if (dcf->dcf_startsym[clockformats[i].endsym / 8] & (1 << (clockformats[i].endsym % 8)))
  537.         {
  538. #ifdef VDDRV
  539.           dcfbusy--;
  540. #endif
  541.           dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - END/START conflict\n")); 
  542.           return OPENFAIL;
  543.         }
  544.       else
  545.         {
  546.           dcf->dcf_endsym[clockformats[i].endsym / 8] |= (1 << (clockformats[i].endsym % 8));
  547.           f = 1;
  548.         }
  549.     }
  550.       if (clockformats[i].flags & SYNC_CHAR)
  551.     {
  552.       dcf->dcf_syncsym[clockformats[i].syncsym / 8] |= (1 << (clockformats[i].syncsym % 8));
  553.     }
  554.       dcf->dcf_syncflags |= clockformats[i].flags & (SYNC_START|SYNC_END|SYNC_CHAR);
  555.       if (dcf->dcf_dsize < clockformats[i].length)
  556.     dcf->dcf_dsize = clockformats[i].length;
  557.     }
  558.   
  559.   if (!f)
  560.     {
  561.       /*
  562.        * need at least one start or end symbol
  563.        */
  564. #ifdef VDDRV
  565.       dcfbusy--;
  566. #endif
  567.       dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - no START/END characters\n")); 
  568.       return OPENFAIL;
  569.     }
  570.  
  571.   dcf->dcf_data = (char *)kmem_alloc(dcf->dcf_dsize * 2 + 2);
  572.   if (!dcf->dcf_data)
  573.     {
  574.       /*
  575.        * can never happen - panics first
  576.        */
  577.       kmem_free((caddr_t)dcf, sizeof(dcf_t));
  578. #ifdef VDDRV
  579.       dcfbusy--;
  580. #endif
  581.       return OPENFAIL;
  582.     }
  583.  
  584.   /*
  585.    * leave room for '\0'
  586.    */
  587.   dcf->dcf_ldata = dcf->dcf_data + dcf->dcf_dsize + 1;
  588.   dcf->dcf_lformat = 0;
  589.   dcf->dcf_badformat = 0;
  590.   
  591.   mp = allocb(sizeof(struct stroptions), BPRI_MED);
  592.   if (mp)
  593.     {
  594.       struct stroptions *str = (struct stroptions *)mp->b_rptr;
  595.  
  596.       str->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT;
  597.       str->so_readopt = RMSGD;
  598.       str->so_hiwat   = sizeof(dcftime_t);
  599.       str->so_lowat   = 0;
  600.       mp->b_datap->db_type = M_SETOPTS;
  601.       mp->b_wptr += sizeof(struct stroptions);
  602.       putnext(q, mp);
  603.       if (putctl1(WR(q)->q_next, M_CTL, MC_SERVICEIMM))
  604.     {
  605.       dcfprintf(DD_OPEN,("dcf77: OPEN - SUCCEEDED\n")); 
  606.       return 1;
  607.     }
  608.       else
  609.     {
  610. #ifdef VDDRV
  611.       dcfbusy--;
  612. #endif
  613.       dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - no MC_SERVICEIMM\n")); 
  614.       return OPENFAIL;
  615.     }
  616.     }
  617.   else
  618.     {
  619. #ifdef VDDRV
  620.       dcfbusy--;
  621. #endif
  622.       dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - no MEMORY for allocb\n")); 
  623.       return OPENFAIL;
  624.     }
  625. }
  626.  
  627. /*ARGSUSED*/
  628. static int dcfclose(q, flags)
  629.   queue_t *q;
  630.   int flags;
  631. {
  632.   register dcf_t *dcf = (dcf_t *)q->q_ptr;
  633.   
  634.   dcfprintf(DD_CLOSE,("dcf77: CLOSE\n"));
  635.   
  636.   if (dcf->dcf_data)
  637.     kmem_free((caddr_t)dcf->dcf_data, dcf->dcf_dsize * 2 + 2);
  638.   
  639.   kmem_free((caddr_t)dcf, sizeof(dcf_t));
  640.  
  641.   q->q_ptr = (caddr_t)NULL;
  642.   WR(q)->q_ptr = (caddr_t)NULL;
  643.  
  644. #ifdef VDDRV
  645.   dcfbusy--;
  646. #endif
  647. }
  648.  
  649. static dcfrsvc(q)
  650.   queue_t *q;
  651. {
  652.   mblk_t *mp;
  653.   
  654.   while (mp = getq(q))
  655.     {
  656.       if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
  657.     {
  658.       putnext(q, mp);
  659.           dcfprintf(DD_RSVC,("dcf77: RSVC - putnext\n"));
  660.     }
  661.       else
  662.     {
  663.       putbq(q, mp);
  664.           dcfprintf(DD_RSVC,("dcf77: RSVC - flow control wait\n"));
  665.       break;
  666.     }
  667.     }
  668. }
  669.  
  670. static int dcfwput(q, mp)
  671.   queue_t *q;
  672.   register mblk_t *mp;
  673. {
  674.   register int ok = 1;
  675.   struct iocblk *iocp;
  676.   dcf_t         *dcf = (dcf_t *)q->q_ptr;
  677.   
  678.   dcfprintf(DD_WPUT,("dcf77: dcfwput\n"));
  679.   
  680.   switch (mp->b_datap->db_type)
  681.     {
  682.      default:
  683.       putnext(q, mp);
  684.       break;
  685.       
  686.      case M_IOCTL:
  687.       iocp = (struct iocblk *)mp->b_rptr;
  688.       switch (iocp->ioc_cmd)
  689.     {
  690.      default:
  691.       dcfprintf(DD_WPUT,("dcf77: dcfwput - forward M_IOCTL\n"));
  692.       putnext(q, mp);
  693.       break;
  694.  
  695.     case DCFIOC_SETSTAT:
  696.     case DCFIOC_GETSTAT:
  697.     case DCFIOC_TIMECODE:
  698.     case DCFIOC_GETFMT:
  699.       if (iocp->ioc_count == sizeof(dcfctl_t))
  700.         {
  701.           dcfctl_t *dct = (dcfctl_t *)mp->b_cont->b_rptr;
  702.  
  703.           switch (iocp->ioc_cmd)
  704.         {
  705.         case DCFIOC_GETSTAT:
  706.           dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_GETSTAT\n"));
  707.           dct->dcfstatus.flags = dcf->dcf_flags;
  708.           break;
  709.           
  710.         case DCFIOC_SETSTAT:
  711.           dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_SETSTAT\n"));
  712.           dcf->dcf_flags = dct->dcfstatus.flags;
  713.           break;
  714.           
  715.         case DCFIOC_TIMECODE:
  716.           dct->dcfgettc.dcf_state = dcf->dcf_lstate;
  717.           dct->dcfgettc.dcf_format = dcf->dcf_lformat;
  718.           /*
  719.            * move out current bad packet count
  720.            * user program is expected to sum these up
  721.            * this is not a problem, as "dcf" module are
  722.            * exclusive open only
  723.            */
  724.           dct->dcfgettc.dcf_badformat = dcf->dcf_badformat;
  725.           dcf->dcf_badformat = 0;
  726.           
  727.           if (dcf->dcf_ldsize <= DCF_TCMAX)
  728.             {
  729.               dct->dcfgettc.dcf_count = dcf->dcf_ldsize;
  730.               bcopy(dcf->dcf_ldata, dct->dcfgettc.dcf_buffer, dct->dcfgettc.dcf_count);
  731.               dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_TIMECODE - ok\n"));
  732.             }
  733.           else
  734.             {
  735.               dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_TIMECODE - FAILED\n"));
  736.               ok = 0;
  737.             }
  738.           break;
  739.           
  740.         case DCFIOC_GETFMT:
  741.           if (dct->dcfgetformat.dcf_format < nformats &&
  742.               strlen(clockformats[dct->dcfgetformat.dcf_format].name) <= DCF_TCMAX)
  743.             {
  744.               dct->dcfgetformat.dcf_count = strlen(clockformats[dct->dcfgetformat.dcf_format].name)+1;
  745.               bcopy(clockformats[dct->dcfgetformat.dcf_format].name, dct->dcfgetformat.dcf_buffer, dct->dcfgetformat.dcf_count);
  746.               dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_GETFMT - ok\n"));
  747.             }
  748.           else
  749.             {
  750.               dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_GETFMT - FAILED\n"));
  751.               ok = 0;
  752.             }
  753.           break;
  754.         }  
  755.           mp->b_datap->db_type = ok ? M_IOCACK : M_IOCNAK;
  756.         }
  757.       else
  758.         {
  759.           mp->b_datap->db_type = M_IOCNAK;
  760.         }
  761.       qreply(q, mp);
  762.       break;
  763.     }
  764.     }
  765. }
  766.  
  767. static int rdchar(mp)
  768.   register mblk_t **mp;
  769. {
  770.   while (*mp != (mblk_t *)NULL)
  771.     {
  772.       if ((*mp)->b_wptr - (*mp)->b_rptr)
  773.     {
  774.       return (int)(*(unsigned char *)((*mp)->b_rptr++) & 0x7F);
  775.     }
  776.       else
  777.     {
  778.       register mblk_t *mmp = *mp;
  779.       
  780.       *mp = (*mp)->b_cont;
  781.       freeb(mmp);
  782.     }
  783.     }
  784.   return -1;
  785. }
  786.  
  787. static int dcfrput(q, mp)
  788.   queue_t *q;
  789.   mblk_t *mp;
  790. {
  791.   switch (mp->b_datap->db_type)
  792.     {
  793.      default:
  794.       dcfprintf(DD_RPUT,("dcf77: dcfrput - forward\n"));
  795.       if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
  796.     {
  797.       putnext(q, mp);
  798.     }
  799.       else
  800.     putq(q, mp);
  801.       break;
  802.       
  803.      case M_DATA:
  804.       {
  805.     register dcf_t * dcf = (dcf_t *)q->q_ptr;
  806.     struct timeval ctime;
  807.  
  808.     /*
  809.      * get time on packet delivery
  810.      */
  811.     uniqtime(&ctime);
  812.     
  813.     dcfprintf(DD_RPUT,("dcf77: dcfrput - M_DATA\n"));
  814.     /*
  815.      * parse packet looking for start an end characters
  816.      */
  817.     while (mp != (mblk_t *)NULL)
  818.       {
  819.         int ch = rdchar(&mp);
  820.  
  821.         if (ch != -1)
  822.           {
  823.         if ((dcf->dcf_syncflags & SYNC_CHAR) &&
  824.             (dcf->dcf_syncsym[ch / 8] & (1 << (ch % 8))))
  825.           {
  826.             register int i;
  827.             /*
  828.              * got a sync event - call sync routine
  829.              */
  830.  
  831.             for (i = 0; i < nformats; i++)
  832.               {
  833.             if ((clockformats[i].flags & SYNC_CHAR) &&
  834.                 (clockformats[i].syncsym == ch))
  835.               {
  836.                 clockformats[i].syncevt(dcf, &ctime, clockformats[i].data, SYNC_CHAR);
  837.                 dcfprintf(DD_RPUT,("dcf77: dcfrput - SYNC (%d - CHAR)\n", i));
  838.               }
  839.               }
  840.           }
  841.         
  842.         if (dcf->dcf_startsym[ch / 8] & (1 << (ch % 8))) 
  843.           {
  844.             register int i;
  845.             /*
  846.              * packet start - re-fill buffer
  847.              */
  848.             if (dcf->dcf_index)
  849.               {
  850.             /*
  851.              * filled buffer - thus not end charcter found
  852.              * do processing now
  853.              */
  854.             dcf->dcf_data[dcf->dcf_index] = '\0';
  855.             bcopy(dcf->dcf_data, dcf->dcf_ldata, dcf->dcf_index+1);
  856.             dcf->dcf_ldsize = dcf->dcf_index+1;
  857.             
  858.             dcfprintf(DD_RPUT,("dcf77: dcfrput - PROCESS (colliding START)\n", i));
  859.             timepacket(dcf);
  860.               }
  861.             /*
  862.              * could be a sync event - call sync routine if needed
  863.              */
  864.             if (dcf->dcf_syncflags & SYNC_START)
  865.               for (i = 0; i < nformats; i++)
  866.             {
  867.               if (clockformats[i].flags & SYNC_START)
  868.                 {
  869.                   clockformats[i].syncevt(dcf, &ctime, clockformats[i].data, SYNC_START);
  870.                   dcfprintf(DD_RPUT,("dcf77: dcfrput - SYNC (%d - START)\n", i));
  871.                 }
  872.             }
  873.             dcf->dcf_index = 1;
  874.             dcf->dcf_data[0] = ch;
  875.           }
  876.         else
  877.           {
  878.             register int i;
  879.  
  880.             if (dcf->dcf_index < dcf->dcf_dsize)
  881.               {
  882.             /*
  883.              * collect into buffer
  884.              */
  885.             dcf->dcf_data[dcf->dcf_index++] = ch;
  886.               }
  887.             if ((dcf->dcf_endsym[ch / 8] & (1 << (ch % 8))) ||
  888.             (dcf->dcf_index >= dcf->dcf_dsize))
  889.               {
  890.             /*
  891.              * packet end - process buffer
  892.              */
  893.             if (dcf->dcf_syncflags & SYNC_END)
  894.               for (i = 0; i < nformats; i++)
  895.                 {
  896.                   if (clockformats[i].flags & SYNC_END)
  897.                 {
  898.                   clockformats[i].syncevt(dcf, &ctime, clockformats[i].data, SYNC_END);
  899.                   dcfprintf(DD_RPUT,("dcf77: dcfrput - SYNC (%d - END)\n", i));
  900.                 }
  901.                 }
  902.             dcf->dcf_data[dcf->dcf_index] = '\0';
  903.             bcopy(dcf->dcf_data, dcf->dcf_ldata, dcf->dcf_index+1);
  904.             dcf->dcf_ldsize = dcf->dcf_index+1;
  905.             
  906.             dcfprintf(DD_RPUT,("dcf77: dcfrput - PROCESS (END)\n"));
  907.             timepacket(dcf);
  908.             dcf->dcf_index = 0;
  909.               }
  910.           }
  911.           }
  912.       }
  913.     break;
  914.       }
  915.     }
  916. }
  917.  
  918. /*---------- conversion implementation --------------------*/
  919.  
  920. /*
  921.  * convert a struct clock to UTC since Jan, 1st 1970 0:00 (the UNIX EPOCH)
  922.  */
  923. #define dysize(x) ((x) % 4 ? 365 : ((x % 400) ? 365 :366))
  924.  
  925. static time_t dcf_to_unixtime(clock)
  926.   clocktime_t *clock;
  927. {
  928.   static int days_of_month[] = 
  929.     {
  930.       0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  931.     };
  932.   register int i;
  933.   time_t t;
  934.   
  935.   if (clock->year < 100)
  936.     clock->year += 1900;
  937.  
  938.   if (clock->year < 1970)
  939.     clock->year += 100;        /* XXX this will do it till <2070 */
  940.  
  941.   if (clock->year < 0)
  942.     return -1;
  943.   
  944.   t =  (clock->year - 1970) * 365;
  945.   t += clock->year / 4 - 1970 / 4;
  946.   t -= clock->year / 400 - 1970 / 400;
  947.  
  948.                   /* month */
  949.   if (clock->month <= 0 || clock->month > 12)
  950.     {
  951.       return -1;        /* bad month */
  952.     }
  953.                 /* adjust leap year */
  954.   if (clock->month >= 3 && dysize(clock->year) == 366)
  955.       t++;
  956.  
  957.   for (i = 1; i < clock->month; i++)
  958.     {
  959.       t += days_of_month[i];
  960.     }
  961.                 /* day */
  962.   if (clock->day < 1 || ((clock->month == 2 && dysize(clock->year) == 366) ?
  963.           clock->day > 29 : clock->day > days_of_month[clock->month]))
  964.     {
  965.       return -1;        /* bad day */
  966.     }
  967.  
  968.   t += clock->day - 1;
  969.                 /* hour */
  970.   if (clock->hour < 0 || clock->hour >= 24)
  971.     {
  972.       return -1;        /* bad hour */
  973.     }
  974.  
  975.   t = 24 * t + clock->hour;
  976.  
  977.                   /* min */
  978.   if (clock->minute < 0 || clock->minute > 59)
  979.     {
  980.       return -1;        /* bad min */
  981.     }
  982.  
  983.   t = 60*t + clock->minute;
  984.                 /* sec */
  985.   
  986.   t += clock->utcoffset;    /* warp to UTC */
  987.  
  988.   if (clock->second < 0 || clock->second > 60)    /* allow for LEAPs */
  989.     {
  990.       return -1;        /* bad sec */
  991.     }
  992.  
  993.   t  = 60*t + clock->second;
  994.                 /* done */
  995.   return t;
  996. }
  997.  
  998. /*--------------- format conversion -----------------------------------*/
  999.  
  1000. static int stoi(s, zp, cnt)
  1001.   char *s;
  1002.   long *zp;
  1003.   int cnt;
  1004. {
  1005.   char *b = s;
  1006.   int f,z,v;
  1007.   char c;
  1008.  
  1009.   f=z=v=0;
  1010.  
  1011.   while(*s == ' ')
  1012.     s++;
  1013.   
  1014.   if (*s == '-')
  1015.     {
  1016.       s++;
  1017.       v = 1;
  1018.     }
  1019.   else
  1020.     if (*s == '+')
  1021.       s++;
  1022.   
  1023.   for(;;)
  1024.     {
  1025.       c = *s++;
  1026.       if (c == '\0' || c < '0' || c > '9' || (cnt && ((s-b) > cnt)))
  1027.     {
  1028.       if (f == 0)
  1029.         {
  1030.           return(-1);
  1031.         }
  1032.       if (v)
  1033.         z = -z;
  1034.       *zp = z;
  1035.       return(0);
  1036.     }
  1037.       z = (z << 3) + (z << 1) + ( c - '0' );
  1038.       f=1;
  1039.     }
  1040. }
  1041.  
  1042. #define CVT_NONE 0
  1043. #define CVT_FAIL 1
  1044. #define CVT_OK   2
  1045.  
  1046.  
  1047. static strok(s, m)
  1048.   char *s;
  1049.   char *m;
  1050. {
  1051.   if (!s || !m)
  1052.     return 0;
  1053.  
  1054.   while(*s && *m)
  1055.     {
  1056.       if ((*m == ' ') ? 1 : (*s == *m))
  1057.     {
  1058.       s++;
  1059.       m++;
  1060.     }
  1061.       else
  1062.     {
  1063.       return 0;
  1064.     }
  1065.     }
  1066.   return !*m;
  1067. }
  1068.  
  1069. /*
  1070.  * cvt_simple
  1071.  *
  1072.  * convert simple type format
  1073.  */
  1074. static cvt_simple(buffer, format, clock)
  1075.   register char          *buffer;
  1076.   register struct format *format;
  1077.   register clocktime_t   *clock;
  1078. {
  1079.   if (!strok(buffer, format->fixed_string))
  1080.     {
  1081.       return CVT_NONE;
  1082.     }
  1083.   else
  1084.     {
  1085.       if (stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day,
  1086.            format->field_offsets[O_DAY].length) ||
  1087.       stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month,
  1088.            format->field_offsets[O_MONTH].length) ||
  1089.       stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year,
  1090.            format->field_offsets[O_YEAR].length) ||
  1091.       stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour,
  1092.            format->field_offsets[O_HOUR].length) ||
  1093.       stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute,
  1094.            format->field_offsets[O_MIN].length) ||
  1095.       stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second,
  1096.            format->field_offsets[O_SEC].length))
  1097.     {
  1098.       return CVT_FAIL;
  1099.     }
  1100.       else
  1101.     {
  1102.       char *f = &buffer[format->field_offsets[O_FLAGS].offset];
  1103.       
  1104.       clock->flags = 0;
  1105.       clock->usecond = 0;
  1106.  
  1107.       switch (buffer[format->field_offsets[O_ZONE].offset])
  1108.         {
  1109.         case ' ':
  1110.           clock->utcoffset = -60; /* MET */
  1111.           break;
  1112.  
  1113.         case 'S':
  1114.           clock->utcoffset = -120; /* MED */
  1115.           clock->flags    |= DCFB_DST;
  1116.           break;
  1117.  
  1118.         case 'U':
  1119.           clock->utcoffset = 0; /* UTC */
  1120.           clock->flags    |= DCFB_UTC;
  1121.           break;
  1122.  
  1123.         default:
  1124.           return CVT_FAIL;
  1125.         }
  1126.  
  1127.       if (f[0] == '#')
  1128.         clock->flags |= DCFB_POWERUP;
  1129.  
  1130.       if (f[1] == '*')
  1131.         clock->flags |= DCFB_NOSYNC;
  1132.       if (f[3] == '!')
  1133.         clock->flags |= DCFB_ANNOUNCE;
  1134.       
  1135.       if (format->flags & MBG_EXTENDED)
  1136.         {
  1137.           clock->flags |= DCFB_S_LEAP;
  1138.           clock->flags |= DCFB_S_LOCATION;
  1139.           
  1140.           if (f[4] == 'L')
  1141.         clock->flags |= DCFB_LEAP;
  1142.           if (f[5] == 'R')
  1143.         clock->flags |= DCFB_ALTERNATE;
  1144.         }
  1145.       return CVT_OK;
  1146.     }
  1147.     }
  1148. }
  1149.  
  1150. /*
  1151.  * cvt_dcf7000
  1152.  *
  1153.  * convert dcf7000 type format
  1154.  */
  1155. static cvt_dcf7000(buffer, format, clock)
  1156.   register char          *buffer;
  1157.   register struct format *format;
  1158.   register clocktime_t   *clock;
  1159. {
  1160.   if (!strok(buffer, format->fixed_string))
  1161.     {
  1162.       return CVT_NONE;
  1163.     }
  1164.   else
  1165.     {
  1166.       if (stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day,
  1167.            format->field_offsets[O_DAY].length) ||
  1168.       stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month,
  1169.            format->field_offsets[O_MONTH].length) ||
  1170.       stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year,
  1171.            format->field_offsets[O_YEAR].length) ||
  1172.       stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour,
  1173.            format->field_offsets[O_HOUR].length) ||
  1174.       stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute,
  1175.            format->field_offsets[O_MIN].length) ||
  1176.       stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second,
  1177.            format->field_offsets[O_SEC].length))
  1178.     {
  1179.       return CVT_FAIL;
  1180.     }
  1181.       else
  1182.     {
  1183.       char *f = &buffer[format->field_offsets[O_FLAGS].offset];
  1184.       int flags;
  1185.       
  1186.       clock->flags = 0;
  1187.       clock->usecond = 0;
  1188.  
  1189.       if (stoi(f, &flags, format->field_offsets[O_FLAGS].length))
  1190.         {
  1191.           return CVT_FAIL;
  1192.         }
  1193.       else
  1194.         {
  1195.           if (flags & 0x1)
  1196.         clock->utcoffset = -120;
  1197.           else
  1198.         clock->utcoffset = -60;
  1199.  
  1200.           if (flags & 0x2)
  1201.         clock->flags |= DCFB_ANNOUNCE;
  1202.  
  1203.           if (flags & 0x4)
  1204.         clock->flags |= DCFB_NOSYNC;
  1205.         }
  1206.       return CVT_OK;
  1207.     }
  1208.     }
  1209. }
  1210.  
  1211. /*
  1212.  * syn_simple
  1213.  *
  1214.  * handle a sync time stamp
  1215.  */
  1216. /*ARGSUSED*/
  1217. static void syn_simple(dcf, tv, format, why)
  1218.   register dcf_t *dcf;
  1219.   register struct timeval *tv;
  1220.   register struct format *format;
  1221.   register unsigned long why;
  1222. {
  1223.   dcf->dcf_stime = *tv;
  1224. }
  1225.  
  1226. /*
  1227.  * timepacket
  1228.  *
  1229.  * process a data packet
  1230.  */
  1231. static void timepacket(dcf)
  1232.   register dcf_t *dcf;
  1233. {
  1234.   register int s, k;
  1235.   register unsigned short format;
  1236.   register long mean;
  1237.   register time_t t;
  1238.   long delta[DCF_DELTA];
  1239.   dcftime_t dtime;
  1240.   clocktime_t clock;
  1241.   mblk_t *nmp;
  1242.   
  1243.   /*
  1244.    * find correct conversion routine
  1245.    * and convert time packet
  1246.    * RR search starting at last successful conversion routine
  1247.    */
  1248.   k = 0;
  1249.   format = dcf->dcf_lformat;
  1250.   
  1251.   if (nformats)            /* very careful ... */
  1252.     {
  1253.       do
  1254.     {
  1255.       switch (clockformats[format].convert(dcf->dcf_data, clockformats[format].data, &clock))
  1256.         {
  1257.         case CVT_FAIL:
  1258.           dcf->dcf_badformat++;
  1259.           /*
  1260.            * may be too often ... but is nice to know when it happens
  1261.            */
  1262.           printf("dcf77: \"%s\" failed to convert\n", clockformats[format].name);
  1263.           /*FALLTHROUGH*/
  1264.         case CVT_NONE:
  1265.           format++;
  1266.           break;
  1267.       
  1268.         case CVT_OK:
  1269.           k = 1;
  1270.           break;
  1271.  
  1272.         default:
  1273.           /* shouldn't happen */
  1274.           printf("dcf77: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format].name);
  1275.       
  1276.           return;
  1277.         }
  1278.       if (format >= nformats)
  1279.         format = 0;
  1280.     }
  1281.       while (!k && (format != dcf->dcf_lformat));
  1282.     }
  1283.   
  1284.   if (!k)
  1285.     {
  1286.       printf("dcf77: time format \"%s\" not convertable\n", dcf->dcf_data);
  1287.       return;
  1288.     }
  1289.  
  1290.   if ((t = dcf_to_unixtime(&clock)) == -1)
  1291.     {
  1292.       printf("dcf77: bad time format \"%s\"\n", dcf->dcf_data);
  1293.       return;
  1294.     }
  1295.   
  1296.   dcf->dcf_lformat = format;
  1297.  
  1298.   /*
  1299.    * filtering (median) if requested
  1300.    */
  1301.   if (dcf->dcf_flags & DCF_STAT_FILTER)
  1302.     {
  1303.       dcf->dcf_delta[dcf->dcf_dindex] = s = (t - dcf->dcf_stime.tv_sec) * 1000000 - dcf->dcf_stime.tv_usec + clock.usecond;
  1304.       dcf->dcf_dindex = (dcf->dcf_dindex + 1) % DCF_DELTA;
  1305.  
  1306.       bcopy((caddr_t)dcf->dcf_delta, (caddr_t)delta, sizeof(delta));
  1307.   
  1308.       for (s = 0; s < DCF_DELTA; s++)
  1309.     for (k = s+1; k < DCF_DELTA; k++)
  1310.       {
  1311.         if (delta[s] > delta[k]) 
  1312.           {
  1313.         register long tmp;
  1314.         
  1315.         tmp      = delta[k];
  1316.         delta[k] = delta[s];
  1317.         delta[s] = tmp;
  1318.           }
  1319.       }
  1320.  
  1321.       mean = 0;
  1322.       for (s = DCF_DELTA / 2 - DCF_DELTA / 4; s < (DCF_DELTA / 2 + DCF_DELTA / 4); s++)
  1323.     {
  1324.       mean += delta[s];
  1325.     }
  1326.  
  1327.       mean /= DCF_DELTA / 2;
  1328.       
  1329.       dcf->dcf_usecerror = mean;
  1330.       /*
  1331.        * assumption: DCF_DELTA / 2 >= 1
  1332.        */
  1333.       dcf->dcf_usecdisp  = delta[DCF_DELTA / 2 + DCF_DELTA / 4 - 1] -
  1334.                        delta[DCF_DELTA / 2 - DCF_DELTA / 4];
  1335.     }
  1336.   else
  1337.     {
  1338.       dcf->dcf_usecerror = (t - dcf->dcf_stime.tv_sec) * 1000000 - dcf->dcf_stime.tv_usec + clock.usecond;
  1339.       dcf->dcf_usecdisp  = 0;
  1340.     }
  1341.   
  1342.  
  1343.   /*
  1344.    * register sample time
  1345.    */
  1346.   dtime.dcf_stime = dcf->dcf_stime;
  1347.  
  1348.   /*
  1349.    * time stamp
  1350.    */
  1351.   dtime.dcf_time.tv_sec  = t;
  1352.   dtime.dcf_time.tv_usec = clock.usecond;
  1353.  
  1354.   /*
  1355.    * derived usec error
  1356.    */
  1357.   dtime.dcf_usecerror    = dcf->dcf_usecerror;
  1358.  
  1359.   /*
  1360.    * filter statistics
  1361.    */
  1362.   dtime.dcf_usecdisp     = dcf->dcf_usecdisp;
  1363.   dtime.dcf_flags        = dcf->dcf_flags;
  1364.   dtime.dcf_format       = format;
  1365.   dtime.dcf_state        = clock.flags;
  1366.  
  1367.   dcf->dcf_lstate     = clock.flags;
  1368.   
  1369.   /*
  1370.    * up up and away (hopefully ...)
  1371.    */
  1372.   nmp = (mblk_t *)NULL;
  1373.   if (canput(dcf->dcf_queue->q_next) && (nmp = allocb(sizeof(dcftime_t), BPRI_MED)))
  1374.     {
  1375.       bcopy((caddr_t)&dtime, (caddr_t)nmp->b_rptr, sizeof(dcftime_t));
  1376.       nmp->b_wptr += sizeof(dcftime_t);
  1377.       putnext(dcf->dcf_queue, nmp);
  1378.     }
  1379.   else
  1380.     if (nmp) freemsg(nmp);
  1381. }
  1382.  
  1383.  
  1384.  
  1385.