Change the default for ntpd back to -s, the bug which triggered this
[dragonfly.git] / contrib / ntp / libparse / parsestreams.c
1 /*
2  * /src/NTP/ntp-4/libparse/parsestreams.c,v 4.7 1999/11/28 09:13:53 kardel RELEASE_19991128_A
3  *  
4  * parsestreams.c,v 4.7 1999/11/28 09:13:53 kardel RELEASE_19991128_A
5  *
6  * STREAMS module for reference clocks
7  * (SunOS4.x)
8  *
9  * Copyright (c) 1989-1998 by Frank Kardel
10  * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
11  *                                    
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  */
17
18 #define KERNEL                  /* MUST */
19 #define VDDRV                   /* SHOULD */
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #ifndef lint
26 static char rcsid[] = "parsestreams.c,v 4.7 1999/11/28 09:13:53 kardel RELEASE_19991128_A";
27 #endif
28
29 #ifndef KERNEL
30 #include "Bletch: MUST COMPILE WITH KERNEL DEFINE"
31 #endif
32
33 #include <sys/types.h>
34 #include <sys/conf.h>
35 #include <sys/buf.h>
36 #include <sys/param.h>
37 #include <sys/sysmacros.h>
38 #include <sys/time.h>
39 #include <sundev/mbvar.h>
40 #include <sun/autoconf.h>
41 #include <sys/stream.h>
42 #include <sys/stropts.h>
43 #include <sys/dir.h>
44 #include <sys/signal.h>
45 #include <sys/termios.h>
46 #include <sys/termio.h>
47 #include <sys/ttold.h>
48 #include <sys/user.h>
49 #include <sys/tty.h>
50
51 #ifdef VDDRV
52 #include <sun/vddrv.h>
53 #endif
54
55 #include "ntp_stdlib.h"
56 #include "ntp_fp.h"
57 /*
58  * just make checking compilers more silent
59  */
60 extern int printf      P((const char *, ...));
61 extern int putctl1     P((queue_t *, int, int));
62 extern int canput      P((queue_t *));
63 extern void putbq      P((queue_t *, mblk_t *));
64 extern void freeb      P((mblk_t *));
65 extern void qreply     P((queue_t *, mblk_t *));
66 extern void freemsg    P((mblk_t *));
67 extern void panic      P((const char *, ...));
68 extern void usec_delay P((int));
69
70 #include "parse.h"
71 #include "sys/parsestreams.h"
72
73 /*
74  * use microtime instead of uniqtime if advised to
75  */
76 #ifdef MICROTIME
77 #define uniqtime microtime
78 #endif
79
80 #ifdef VDDRV
81 static unsigned int parsebusy = 0;
82
83 /*--------------- loadable driver section -----------------------------*/
84
85 extern struct streamtab parseinfo;
86
87
88 #ifdef PPS_SYNC
89 static char mnam[] = "PARSEPPS     ";   /* name this baby - keep room for revision number */
90 #else
91 static char mnam[] = "PARSE        ";   /* name this baby - keep room for revision number */
92 #endif
93 struct vdldrv parsesync_vd = 
94 {
95         VDMAGIC_PSEUDO,         /* nothing like a real driver - a STREAMS module */
96         mnam,
97 };
98
99 /*
100  * strings support usually not in kernel
101  */
102 static int
103 Strlen(
104         register const char *s
105         )
106 {
107         register int c;
108
109         c = 0;
110         if (s)
111         {
112                 while (*s++)
113                 {
114                         c++;
115                 }
116         }
117         return c;
118 }
119
120 static void
121 Strncpy(
122         register char *t,
123         register char *s,
124         register int   c
125         )
126 {
127         if (s && t)
128         {
129                 while ((c-- > 0) && (*t++ = *s++))
130                     ;
131         }
132 }
133
134 static int
135 Strcmp(
136         register const char *s,
137         register const char *t
138         )
139 {
140         register int c = 0;
141
142         if (!s || !t || (s == t))
143         {
144                 return 0;
145         }
146
147         while (!(c = *s++ - *t++) && *s && *t)
148             /* empty loop */;
149   
150         return c;
151 }
152
153 static int
154 Strncmp(
155         register char *s,
156         register char *t,
157         register int n
158         )
159 {
160         register int c = 0;
161
162         if (!s || !t || (s == t))
163         {
164                 return 0;
165         }
166
167         while (n-- && !(c = *s++ - *t++) && *s && *t)
168             /* empty loop */;
169   
170         return c;
171 }
172  
173 void
174 ntp_memset(
175         char *a,
176         int x,
177         int c
178         )
179 {
180         while (c-- > 0)
181             *a++ = x;
182 }
183
184 /*
185  * driver init routine
186  * since no mechanism gets us into and out of the fmodsw, we have to
187  * do it ourselves
188  */
189 /*ARGSUSED*/
190 int
191 xxxinit(
192         unsigned int fc,
193         struct vddrv *vdp,
194         addr_t vdin,
195         struct vdstat *vds
196         )
197 {
198         extern struct fmodsw fmodsw[];
199         extern int fmodcnt;
200   
201         struct fmodsw *fm    = fmodsw;
202         struct fmodsw *fmend = &fmodsw[fmodcnt];
203         struct fmodsw *ifm   = (struct fmodsw *)0;
204         char *mname          = parseinfo.st_rdinit->qi_minfo->mi_idname;
205   
206         switch (fc)
207         {
208             case VDLOAD:
209                 vdp->vdd_vdtab = (struct vdlinkage *)&parsesync_vd;
210                 /*
211                  * now, jog along fmodsw scanning for an empty slot
212                  * and deposit our name there
213                  */
214                 while (fm <= fmend)
215                 {
216           if (!Strncmp(fm->f_name, mname, FMNAMESZ))
217                         {
218                                 printf("vddrinit[%s]: STREAMS module already loaded.\n", mname);
219                                 return(EBUSY);
220                         }
221                         else
222                             if ((ifm == (struct fmodsw *)0) && 
223                                 (fm->f_name[0] == '\0') &&
224                                 (fm->f_str == (struct streamtab *)0))
225                             {
226                                     /*
227                                      * got one - so move in
228                                      */
229                                     ifm = fm;
230                                     break;
231                             }
232                         fm++;
233                 }
234
235                 if (ifm == (struct fmodsw *)0)
236                 {
237                         printf("vddrinit[%s]: no slot free for STREAMS module\n", mname);
238                         return (ENOSPC);
239                 }
240                 else
241                 {
242                         static char revision[] = "4.7";
243                         char *s, *S, *t;
244           
245                         s = rcsid;              /* NOOP - keep compilers happy */
246
247                         Strncpy(ifm->f_name, mname, FMNAMESZ);
248                         ifm->f_name[FMNAMESZ] = '\0';
249                         ifm->f_str = &parseinfo;
250                         /*
251                          * copy RCS revision into Drv_name
252                          *
253                          * are we forcing RCS here to do things it was not built for ?
254                          */
255                         s = revision;
256                         if (*s == '$')
257                         {
258                                 /*
259                                  * skip "$Revision: "
260                                  * if present. - not necessary on a -kv co (cvs export)
261                                  */
262                                 while (*s && (*s != ' '))
263                                 {
264                                         s++;
265                                 }
266                                 if (*s == ' ') s++;
267                         }
268           
269                         t = parsesync_vd.Drv_name; 
270                         while (*t && (*t != ' '))
271                         {
272                                 t++;
273                         }
274                         if (*t == ' ') t++;
275           
276                         S = s;
277                         while (*S && (((*S >= '0') && (*S <= '9')) || (*S == '.')))
278                         {
279                                 S++;
280                         }
281           
282                         if (*s && *t && (S > s))
283                         {
284                                 if (Strlen(t) >= (S - s))
285                                 {
286                                         (void) Strncpy(t, s, S - s);
287                                 }
288                         }
289                         return (0);
290                 } 
291                 break;
292       
293             case VDUNLOAD:
294                 if (parsebusy > 0)
295                 {
296                         printf("vddrinit[%s]: STREAMS module has still %d instances active.\n", mname, parsebusy);
297                         return (EBUSY);
298                 }
299                 else
300                 {
301                         while (fm <= fmend)
302                         {
303                                 if (!Strncmp(fm->f_name, mname, FMNAMESZ))
304                                 {
305                                         /*
306                                          * got it - kill entry
307                                          */
308                                         fm->f_name[0] = '\0';
309                                         fm->f_str = (struct streamtab *)0;
310                                         fm++;
311                   
312                                         break;
313                                 }
314                                 fm++;
315                         }
316                         if (fm > fmend)
317                         {
318                                 printf("vddrinit[%s]: cannot find entry for STREAMS module\n", mname);
319                                 return (ENXIO);
320                         }
321                         else
322                             return (0);
323                 }
324       
325
326             case VDSTAT:
327                 return (0);
328
329             default:
330                 return (EIO);
331       
332         }
333         return EIO;
334 }
335
336 #endif
337
338 /*--------------- stream module definition ----------------------------*/
339
340 static int parseopen  P((queue_t *, dev_t, int, int));
341 static int parseclose P((queue_t *, int));
342 static int parsewput  P((queue_t *, mblk_t *));
343 static int parserput  P((queue_t *, mblk_t *));
344 static int parsersvc  P((queue_t *));
345
346 static char mn[] = "parse";
347
348 static struct module_info driverinfo =
349 {
350         0,                              /* module ID number */
351         mn,                     /* module name */
352         0,                              /* minimum accepted packet size */
353         INFPSZ,                 /* maximum accepted packet size */
354         1,                              /* high water mark - flow control */
355         0                               /* low water mark - flow control */
356 };
357
358 static struct qinit rinit =     /* read queue definition */
359 {
360         parserput,                      /* put procedure */
361         parsersvc,                      /* service procedure */
362         parseopen,                      /* open procedure */
363         parseclose,                     /* close procedure */
364         NULL,                           /* admin procedure - NOT USED FOR NOW */
365         &driverinfo,                    /* information structure */
366         NULL                            /* statistics */
367 };
368
369 static struct qinit winit =     /* write queue definition */
370 {
371         parsewput,                      /* put procedure */
372         NULL,                           /* service procedure */
373         NULL,                           /* open procedure */
374         NULL,                           /* close procedure */
375         NULL,                           /* admin procedure - NOT USED FOR NOW */
376         &driverinfo,                    /* information structure */
377         NULL                            /* statistics */
378 };
379
380 struct streamtab parseinfo =    /* stream info element for dpr driver */
381 {
382         &rinit,                 /* read queue */
383         &winit,                 /* write queue */
384         NULL,                           /* read mux */
385         NULL,                           /* write mux */
386         NULL                            /* module auto push */
387 };
388
389 /*--------------- driver data structures ----------------------------*/
390
391 /*
392  * we usually have an inverted signal - but you
393  * can change this to suit your needs
394  */
395 int cd_invert = 1;              /* invert status of CD line - PPS support via CD input */
396
397 int parsedebug = ~0;
398
399 extern void uniqtime P((struct timeval *));
400
401 /*--------------- module implementation -----------------------------*/
402
403 #define TIMEVAL_USADD(_X_, _US_) {\
404                                    (_X_)->tv_usec += (_US_);\
405                                    if ((_X_)->tv_usec >= 1000000)\
406                                      {\
407                                        (_X_)->tv_sec++;\
408                                        (_X_)->tv_usec -= 1000000;\
409                                      }\
410                                  } while (0)
411
412 static int init_linemon P((queue_t *));
413 static void close_linemon P((queue_t *, queue_t *));
414
415 #define M_PARSE         0x0001
416 #define M_NOPARSE       0x0002
417
418 static int
419 setup_stream(
420              queue_t *q,
421              int mode
422              )
423 {
424         mblk_t *mp;
425
426         mp = allocb(sizeof(struct stroptions), BPRI_MED);
427         if (mp)
428         {
429                 struct stroptions *str = (struct stroptions *)(void *)mp->b_rptr;
430
431                 str->so_flags   = SO_READOPT|SO_HIWAT|SO_LOWAT;
432                 str->so_readopt = (mode == M_PARSE) ? RMSGD : RNORM;
433                 str->so_hiwat   = (mode == M_PARSE) ? sizeof(parsetime_t) : 256;
434                 str->so_lowat   = 0;
435                 mp->b_datap->db_type = M_SETOPTS;
436                 mp->b_wptr += sizeof(struct stroptions);
437                 putnext(q, mp);
438                 return putctl1(WR(q)->q_next, M_CTL, (mode == M_PARSE) ? MC_SERVICEIMM :
439                                MC_SERVICEDEF);
440         }
441         else
442         {
443                 parseprintf(DD_OPEN,("parse: setup_stream - FAILED - no MEMORY for allocb\n")); 
444                 return 0;
445         }
446 }
447
448 /*ARGSUSED*/
449 static int
450 parseopen(
451         queue_t *q,
452         dev_t dev,
453         int flag,
454         int sflag
455         )
456 {
457         register parsestream_t *parse;
458         static int notice = 0;
459   
460         parseprintf(DD_OPEN,("parse: OPEN\n")); 
461   
462         if (sflag != MODOPEN)
463         {                       /* open only for modules */
464                 parseprintf(DD_OPEN,("parse: OPEN - FAILED - not MODOPEN\n")); 
465                 return OPENFAIL;
466         }
467
468         if (q->q_ptr != (caddr_t)NULL)
469         {
470                 u.u_error = EBUSY;
471                 parseprintf(DD_OPEN,("parse: OPEN - FAILED - EXCLUSIVE ONLY\n")); 
472                 return OPENFAIL;
473         }
474
475 #ifdef VDDRV
476         parsebusy++;
477 #endif
478   
479         q->q_ptr = (caddr_t)kmem_alloc(sizeof(parsestream_t));
480         if (q->q_ptr == (caddr_t)0)
481         {
482                 parseprintf(DD_OPEN,("parse: OPEN - FAILED - no memory\n")); 
483 #ifdef VDDRV
484                 parsebusy--;
485 #endif
486                 return OPENFAIL;
487         }
488         WR(q)->q_ptr = q->q_ptr;
489   
490         parse = (parsestream_t *)(void *)q->q_ptr;
491         bzero((caddr_t)parse, sizeof(*parse));
492         parse->parse_queue     = q;
493         parse->parse_status    = PARSE_ENABLE;
494         parse->parse_ppsclockev.tv.tv_sec  = 0;
495         parse->parse_ppsclockev.tv.tv_usec = 0;
496         parse->parse_ppsclockev.serial     = 0;
497
498         if (!parse_ioinit(&parse->parse_io))
499         {
500                 /*
501                  * ok guys - beat it
502                  */
503                 kmem_free((caddr_t)parse, sizeof(parsestream_t));
504 #ifdef VDDRV
505                 parsebusy--;
506 #endif
507                 return OPENFAIL;
508         }
509
510         if (setup_stream(q, M_PARSE))
511         {
512                 (void) init_linemon(q); /* hook up PPS ISR routines if possible */
513
514                 parseprintf(DD_OPEN,("parse: OPEN - SUCCEEDED\n")); 
515
516                 /*
517                  * I know that you know the delete key, but you didn't write this
518                  * code, did you ? - So, keep the message in here.
519                  */
520                 if (!notice)
521                 {
522 #ifdef VDDRV
523                         printf("%s: Copyright (C) 1991-1998, Frank Kardel\n", parsesync_vd.Drv_name);
524 #else
525                         printf("%s: Copyright (C) 1991-1998, Frank Kardel\n", "parsestreams.c,v 4.7 1999/11/28 09:13:53 kardel RELEASE_19991128_A");
526 #endif
527                         notice = 1;
528                 }
529
530                 return MODOPEN;
531         }
532         else
533         {
534                 kmem_free((caddr_t)parse, sizeof(parsestream_t));
535
536 #ifdef VDDRV
537                 parsebusy--;
538 #endif
539                 return OPENFAIL;
540         }
541 }
542
543 /*ARGSUSED*/
544 static int
545 parseclose(
546         queue_t *q,
547         int flags
548         )
549 {
550         register parsestream_t *parse = (parsestream_t *)(void *)q->q_ptr;
551         register unsigned long s;
552   
553         parseprintf(DD_CLOSE,("parse: CLOSE\n"));
554   
555         s = splhigh();
556   
557         if (parse->parse_dqueue)
558             close_linemon(parse->parse_dqueue, q);
559         parse->parse_dqueue = (queue_t *)0;
560
561         (void) splx(s);
562       
563         parse_ioend(&parse->parse_io);
564
565         kmem_free((caddr_t)parse, sizeof(parsestream_t));
566
567         q->q_ptr = (caddr_t)NULL;
568         WR(q)->q_ptr = (caddr_t)NULL;
569
570 #ifdef VDDRV
571         parsebusy--;
572 #endif
573         return 0;
574 }
575
576 /*
577  * move unrecognized stuff upward
578  */
579 static int
580 parsersvc(
581         queue_t *q
582         )
583 {
584         mblk_t *mp;
585   
586         while ((mp = getq(q)))
587         {
588                 if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
589                 {
590                         putnext(q, mp);
591                         parseprintf(DD_RSVC,("parse: RSVC - putnext\n"));
592                 }
593                 else
594                 {
595                         putbq(q, mp);
596                         parseprintf(DD_RSVC,("parse: RSVC - flow control wait\n"));
597                         break;
598                 }
599         }
600         return 0;
601 }
602
603 /*
604  * do ioctls and
605  * send stuff down - dont care about
606  * flow control
607  */
608 static int
609 parsewput(
610         queue_t *q,
611         register mblk_t *mp
612         )
613 {
614         register int ok = 1;
615         register mblk_t *datap;
616         register struct iocblk *iocp;
617         parsestream_t         *parse = (parsestream_t *)(void *)q->q_ptr;
618   
619         parseprintf(DD_WPUT,("parse: parsewput\n"));
620   
621         switch (mp->b_datap->db_type)
622         {
623             default:
624                 putnext(q, mp);
625                 break;
626       
627             case M_IOCTL:
628                     iocp = (struct iocblk *)(void *)mp->b_rptr;
629                 switch (iocp->ioc_cmd)
630                 {
631                     default:
632                         parseprintf(DD_WPUT,("parse: parsewput - forward M_IOCTL\n"));
633                         putnext(q, mp);
634                         break;
635
636                     case CIOGETEV:
637                         /*
638                          * taken from Craig Leres ppsclock module (and modified)
639                          */
640                         datap = allocb(sizeof(struct ppsclockev), BPRI_MED);
641                         if (datap == NULL || mp->b_cont)
642                         {
643                                 mp->b_datap->db_type = M_IOCNAK;
644                                 iocp->ioc_error = (datap == NULL) ? ENOMEM : EINVAL;
645                                 if (datap != NULL)
646                                     freeb(datap);
647                                 qreply(q, mp);
648                                 break;
649                         }
650
651                         mp->b_cont = datap;
652                         *(struct ppsclockev *)(void *)datap->b_wptr = parse->parse_ppsclockev;
653                         datap->b_wptr +=
654                                 sizeof(struct ppsclockev) / sizeof(*datap->b_wptr);
655                         mp->b_datap->db_type = M_IOCACK;
656                         iocp->ioc_count = sizeof(struct ppsclockev);
657                         qreply(q, mp);
658                         break;
659           
660                     case PARSEIOC_ENABLE:
661                     case PARSEIOC_DISABLE:
662                             {
663                                     parse->parse_status = (parse->parse_status & (unsigned)~PARSE_ENABLE) |
664                                             (iocp->ioc_cmd == PARSEIOC_ENABLE) ?
665                                             PARSE_ENABLE : 0;
666                                     if (!setup_stream(RD(q), (parse->parse_status & PARSE_ENABLE) ?
667                                                       M_PARSE : M_NOPARSE))
668                                     {
669                                             mp->b_datap->db_type = M_IOCNAK;
670                                     }
671                                     else
672                                     {
673                                             mp->b_datap->db_type = M_IOCACK;
674                                     }
675                                     qreply(q, mp);
676                                     break;
677                             }       
678
679                     case PARSEIOC_TIMECODE:
680                     case PARSEIOC_SETFMT:
681                     case PARSEIOC_GETFMT:
682                     case PARSEIOC_SETCS:
683                         if (iocp->ioc_count == sizeof(parsectl_t))
684                         {
685                                 parsectl_t *dct = (parsectl_t *)(void *)mp->b_cont->b_rptr;
686
687                                 switch (iocp->ioc_cmd)
688                                 {
689                                     case PARSEIOC_TIMECODE:
690                                         parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_TIMECODE\n"));
691                                         ok = parse_timecode(dct, &parse->parse_io);
692                                         break;
693                   
694                                     case PARSEIOC_SETFMT:
695                                         parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETFMT\n"));
696                                         ok = parse_setfmt(dct, &parse->parse_io);
697                                         break;
698
699                                     case PARSEIOC_GETFMT:
700                                         parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_GETFMT\n"));
701                                         ok = parse_getfmt(dct, &parse->parse_io);
702                                         break;
703
704                                     case PARSEIOC_SETCS:
705                                         parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETCS\n"));
706                                         ok = parse_setcs(dct, &parse->parse_io);
707                                         break;
708                                 }
709                                 mp->b_datap->db_type = ok ? M_IOCACK : M_IOCNAK;
710                         }
711                         else
712                         {
713                                 mp->b_datap->db_type = M_IOCNAK;
714                         }
715                         parseprintf(DD_WPUT,("parse: parsewput qreply - %s\n", (mp->b_datap->db_type == M_IOCNAK) ? "M_IOCNAK" : "M_IOCACK"));
716                         qreply(q, mp);
717                         break;
718                 }
719         }
720         return 0;
721 }
722
723 /*
724  * read characters from streams buffers
725  */
726 static unsigned long
727 rdchar(
728        register mblk_t **mp
729        )
730 {
731         while (*mp != (mblk_t *)NULL)
732         {
733                 if ((*mp)->b_wptr - (*mp)->b_rptr)
734                 {
735                         return (unsigned long)(*(unsigned char *)((*mp)->b_rptr++));
736                 }
737                 else
738                 {
739                         register mblk_t *mmp = *mp;
740           
741                         *mp = (*mp)->b_cont;
742                         freeb(mmp);
743                 }
744         }
745         return (unsigned)~0;
746 }
747
748 /*
749  * convert incoming data
750  */
751 static int
752 parserput(
753         queue_t *q,
754         mblk_t *mp
755         )
756 {
757         unsigned char type;
758   
759         switch (type = mp->b_datap->db_type)
760         {
761             default:
762                 /*
763                  * anything we don't know will be put on queue
764                  * the service routine will move it to the next one
765                  */
766                 parseprintf(DD_RPUT,("parse: parserput - forward type 0x%x\n", type));
767                 if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
768                 {
769                         putnext(q, mp);
770                 }
771                 else
772                     putq(q, mp);
773                 break;
774       
775             case M_BREAK:
776             case M_DATA:
777                     {
778                             register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr;
779                             register mblk_t *nmp;
780                             register unsigned long ch;
781                             timestamp_t ctime;
782
783                             /*
784                              * get time on packet delivery
785                              */
786                             uniqtime(&ctime.tv);
787
788                             if (!(parse->parse_status & PARSE_ENABLE))
789                             {
790                                     parseprintf(DD_RPUT,("parse: parserput - parser disabled - forward type 0x%x\n", type));
791                                     if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
792                                     {
793                                             putnext(q, mp);
794                                     }
795                                     else
796                                         putq(q, mp);
797                             }
798                             else
799                             {
800                                     parseprintf(DD_RPUT,("parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK"));
801
802                                     if (type == M_DATA)
803                                     {
804                                             /*
805                                              * parse packet looking for start an end characters
806                                              */
807                                             while (mp != (mblk_t *)NULL)
808                                             {
809                                                     ch = rdchar(&mp);
810                                                     if (ch != ~0 && parse_ioread(&parse->parse_io, (unsigned int)ch, &ctime))
811                                                     {
812                                                             /*
813                                                              * up up and away (hopefully ...)
814                                                              * don't press it if resources are tight or nobody wants it
815                                                              */
816                                                             nmp = (mblk_t *)NULL;
817                                                             if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
818                                                             {
819                                                                     bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
820                                                                     nmp->b_wptr += sizeof(parsetime_t);
821                                                                     putnext(parse->parse_queue, nmp);
822                                                             }
823                                                             else
824                                                                 if (nmp) freemsg(nmp);
825                                                             parse_iodone(&parse->parse_io);
826                                                     }
827                                             }   
828                                     }
829                                     else
830                                     {
831                                             if (parse_ioread(&parse->parse_io, (unsigned int)0, &ctime))
832                                             {
833                                                     /*
834                                                      * up up and away (hopefully ...)
835                                                      * don't press it if resources are tight or nobody wants it
836                                                      */
837                                                     nmp = (mblk_t *)NULL;
838                                                     if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
839                                                     {
840                                                             bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
841                                                             nmp->b_wptr += sizeof(parsetime_t);
842                                                             putnext(parse->parse_queue, nmp);
843                                                     }
844                                                     else
845                                                         if (nmp) freemsg(nmp);
846                                                     parse_iodone(&parse->parse_io);
847                                             }
848                                             freemsg(mp);
849                                     }
850                                     break;
851                             }
852                     }
853
854                     /*
855                      * CD PPS support for non direct ISR hack
856                      */
857             case M_HANGUP:
858             case M_UNHANGUP:
859                     {
860                             register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr;
861                             timestamp_t ctime;
862                             register mblk_t *nmp;
863                             register int status = cd_invert ^ (type == M_UNHANGUP);
864
865                             uniqtime(&ctime.tv);
866         
867                             parseprintf(DD_RPUT,("parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN"));
868
869                             if ((parse->parse_status & PARSE_ENABLE) &&
870                                 parse_iopps(&parse->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &ctime))
871                             {
872                                     nmp = (mblk_t *)NULL;
873                                     if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
874                                     {
875                                             bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
876                                             nmp->b_wptr += sizeof(parsetime_t);
877                                             putnext(parse->parse_queue, nmp);
878                                     }
879                                     else
880                                         if (nmp) freemsg(nmp);
881                                     parse_iodone(&parse->parse_io);
882                                     freemsg(mp);
883                             }
884                             else
885                                 if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
886                                 {
887                                         putnext(q, mp);
888                                 }
889                                 else
890                                     putq(q, mp);
891         
892                             if (status)
893                             {
894                                     parse->parse_ppsclockev.tv = ctime.tv;
895                                     ++(parse->parse_ppsclockev.serial);
896                             }
897                     }
898         }
899         return 0;
900 }
901
902 static int  init_zs_linemon  P((queue_t *, queue_t *)); /* handle line monitor for "zs" driver */
903 static void close_zs_linemon P((queue_t *, queue_t *));
904
905 /*-------------------- CD isr status monitor ---------------*/
906
907 static int
908 init_linemon(
909         register queue_t *q
910         )
911 {
912         register queue_t *dq;
913   
914         dq = WR(q);
915         /*
916          * we ARE doing very bad things down here (basically stealing ISR
917          * hooks)
918          *
919          * so we chase down the STREAMS stack searching for the driver
920          * and if this is a known driver we insert our ISR routine for
921          * status changes in to the ExternalStatus handling hook
922          */
923         while (dq->q_next)
924         {
925                 dq = dq->q_next;                /* skip down to driver */
926         }
927
928         /*
929          * find appropriate driver dependent routine
930          */
931         if (dq->q_qinfo && dq->q_qinfo->qi_minfo)
932         {
933                 register char *dname = dq->q_qinfo->qi_minfo->mi_idname;
934
935                 parseprintf(DD_INSTALL, ("init_linemon: driver is \"%s\"\n", dname));
936
937 #ifdef sun
938                 if (dname && !Strcmp(dname, "zs"))
939                 {
940                         return init_zs_linemon(dq, q);
941                 }
942                 else
943 #endif
944                 {
945                         parseprintf(DD_INSTALL, ("init_linemon: driver \"%s\" not suitable for CD monitoring\n", dname));
946                         return 0;
947                 }
948         }
949         parseprintf(DD_INSTALL, ("init_linemon: cannot find driver\n"));
950         return 0;
951 }
952
953 static void
954 close_linemon(
955         register queue_t *q,
956         register queue_t *my_q
957         )
958 {
959         /*
960          * find appropriate driver dependent routine
961          */
962         if (q->q_qinfo && q->q_qinfo->qi_minfo)
963         {
964                 register char *dname = q->q_qinfo->qi_minfo->mi_idname;
965
966 #ifdef sun
967                 if (dname && !Strcmp(dname, "zs"))
968                 {
969                         close_zs_linemon(q, my_q);
970                         return;
971                 }
972                 parseprintf(DD_INSTALL, ("close_linemon: cannot find driver close routine for \"%s\"\n", dname));
973 #endif
974         }
975         parseprintf(DD_INSTALL, ("close_linemon: cannot find driver name\n"));
976 }
977
978 #ifdef sun
979
980 #include <sundev/zsreg.h>
981 #include <sundev/zscom.h>
982 #include <sundev/zsvar.h>
983
984 static unsigned long cdmask  = ZSRR0_CD;
985
986 struct savedzsops
987 {
988         struct zsops  zsops;
989         struct zsops *oldzsops;
990 };
991
992 struct zsops   *emergencyzs;
993 extern void zsopinit   P((struct zscom *, struct zsops *));
994 static int  zs_xsisr   P((struct zscom *));     /* zs external status interupt handler */
995
996 static int
997 init_zs_linemon(
998         register queue_t *q,
999         register queue_t *my_q
1000         )
1001 {
1002         register struct zscom *zs;
1003         register struct savedzsops *szs;
1004         register parsestream_t  *parsestream = (parsestream_t *)(void *)my_q->q_ptr;
1005         /*
1006          * we expect the zsaline pointer in the q_data pointer
1007          * from there on we insert our on EXTERNAL/STATUS ISR routine
1008          * into the interrupt path, before the standard handler
1009          */
1010         zs = ((struct zsaline *)(void *)q->q_ptr)->za_common;
1011         if (!zs)
1012         {
1013                 /*
1014                  * well - not found on startup - just say no (shouldn't happen though)
1015                  */
1016                 return 0;
1017         }
1018         else
1019         {
1020                 unsigned long s;
1021       
1022                 /*
1023                  * we do a direct replacement, in case others fiddle also
1024                  * if somebody else grabs our hook and we disconnect
1025                  * we are in DEEP trouble - panic is likely to be next, sorry
1026                  */
1027                 szs = (struct savedzsops *)(void *)kmem_alloc(sizeof(struct savedzsops));
1028
1029                 if (szs == (struct savedzsops *)0)
1030                 {
1031                         parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor NOT installed - no memory\n"));
1032
1033                         return 0;
1034                 }
1035                 else
1036                 {
1037                         parsestream->parse_data   = (void *)szs;
1038
1039                         s = splhigh();
1040
1041                         parsestream->parse_dqueue = q; /* remember driver */
1042
1043                         szs->zsops            = *zs->zs_ops;
1044                         szs->zsops.zsop_xsint = zs_xsisr; /* place our bastard */
1045                         szs->oldzsops         = zs->zs_ops;
1046                         emergencyzs           = zs->zs_ops;
1047           
1048                         zsopinit(zs, &szs->zsops); /* hook it up */
1049           
1050                         (void) splx(s);
1051
1052                         parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor installed\n"));
1053
1054                         return 1;
1055                 }
1056         }
1057 }
1058
1059 /*
1060  * unregister our ISR routine - must call under splhigh()
1061  */
1062 static void
1063 close_zs_linemon(
1064         register queue_t *q,
1065         register queue_t *my_q
1066         )
1067 {
1068         register struct zscom *zs;
1069         register parsestream_t  *parsestream = (parsestream_t *)(void *)my_q->q_ptr;
1070
1071         zs = ((struct zsaline *)(void *)q->q_ptr)->za_common;
1072         if (!zs)
1073         {
1074                 /*
1075                  * well - not found on startup - just say no (shouldn't happen though)
1076                  */
1077                 return;
1078         }
1079         else
1080         {
1081                 register struct savedzsops *szs = (struct savedzsops *)parsestream->parse_data;
1082       
1083                 zsopinit(zs, szs->oldzsops); /* reset to previous handler functions */
1084
1085                 kmem_free((caddr_t)szs, sizeof (struct savedzsops));
1086       
1087                 parseprintf(DD_INSTALL, ("close_zs_linemon: CD monitor deleted\n"));
1088                 return;
1089         }
1090 }
1091
1092 #define MAXDEPTH 50             /* maximum allowed stream crawl */
1093
1094 #ifdef PPS_SYNC
1095 extern void hardpps P((struct timeval *, long));
1096 #ifdef PPS_NEW
1097 extern struct timeval timestamp;
1098 #else
1099 extern struct timeval pps_time;
1100 #endif
1101 #endif
1102
1103 /*
1104  * take external status interrupt (only CD interests us)
1105  */
1106 static int
1107 zs_xsisr(
1108          struct zscom *zs
1109         )
1110 {
1111         register struct zsaline *za = (struct zsaline *)(void *)zs->zs_priv;
1112         register struct zscc_device *zsaddr = zs->zs_addr;
1113         register queue_t *q;
1114         register unsigned char zsstatus;
1115         register int loopcheck;
1116         register char *dname;
1117 #ifdef PPS_SYNC
1118         register unsigned int s;
1119         register long usec;
1120 #endif
1121
1122         /*
1123          * pick up current state
1124          */
1125         zsstatus = zsaddr->zscc_control;
1126
1127         if ((za->za_rr0 ^ zsstatus) & (cdmask))
1128         {
1129                 timestamp_t cdevent;
1130                 register int status;
1131       
1132                 za->za_rr0 = (za->za_rr0 & ~(cdmask)) | (zsstatus & (cdmask));
1133
1134 #ifdef PPS_SYNC
1135                 s = splclock();
1136 #ifdef PPS_NEW
1137                 usec = timestamp.tv_usec;
1138 #else
1139                 usec = pps_time.tv_usec;
1140 #endif
1141 #endif
1142                 /*
1143                  * time stamp
1144                  */
1145                 uniqtime(&cdevent.tv);
1146       
1147 #ifdef PPS_SYNC
1148                 (void)splx(s);
1149 #endif
1150
1151                 /*
1152                  * logical state
1153                  */
1154                 status = cd_invert ? (zsstatus & cdmask) == 0 : (zsstatus & cdmask) != 0;
1155
1156 #ifdef PPS_SYNC
1157                 if (status)
1158                 {
1159                         usec = cdevent.tv.tv_usec - usec;
1160                         if (usec < 0)
1161                             usec += 1000000;
1162
1163                         hardpps(&cdevent.tv, usec);
1164                 }
1165 #endif
1166
1167                 q = za->za_ttycommon.t_readq;
1168
1169                 /*
1170                  * ok - now the hard part - find ourself
1171                  */
1172                 loopcheck = MAXDEPTH;
1173       
1174                 while (q)
1175                 {
1176                         if (q->q_qinfo && q->q_qinfo->qi_minfo)
1177                         {
1178                                 dname = q->q_qinfo->qi_minfo->mi_idname;
1179
1180                                 if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname))
1181                                 {
1182                                         /*
1183                                          * back home - phew (hopping along stream queues might
1184                                          * prove dangerous to your health)
1185                                          */
1186
1187                                         if ((((parsestream_t *)(void *)q->q_ptr)->parse_status & PARSE_ENABLE) &&
1188                                             parse_iopps(&((parsestream_t *)(void *)q->q_ptr)->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &cdevent))
1189                                         {
1190                                                 /*
1191                                                  * XXX - currently we do not pass up the message, as
1192                                                  * we should.
1193                                                  * for a correct behaviour wee need to block out
1194                                                  * processing until parse_iodone has been posted via
1195                                                  * a softcall-ed routine which does the message pass-up
1196                                                  * right now PPS information relies on input being
1197                                                  * received
1198                                                  */
1199                                                 parse_iodone(&((parsestream_t *)(void *)q->q_ptr)->parse_io);
1200                                         }
1201                   
1202                                         if (status)
1203                                         {
1204                                                 ((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.tv = cdevent.tv;
1205                                                 ++(((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.serial);
1206                                         }
1207
1208                                         parseprintf(DD_ISR, ("zs_xsisr: CD event %s has been posted for \"%s\"\n", status ? "ONE" : "ZERO", dname));
1209                                         break;
1210                                 }
1211                         }
1212
1213                         q = q->q_next;
1214
1215                         if (!loopcheck--)
1216                         {
1217                                 panic("zs_xsisr: STREAMS Queue corrupted - CD event");
1218                         }
1219                 }
1220
1221                 /*
1222                  * only pretend that CD has been handled
1223                  */
1224                 ZSDELAY(2);
1225
1226                 if (!((za->za_rr0 ^ zsstatus) & ~(cdmask)))
1227                 {
1228                         /*
1229                          * all done - kill status indication and return
1230                          */
1231                         zsaddr->zscc_control = ZSWR0_RESET_STATUS; /* might kill other conditions here */
1232                         return 0;
1233                 }
1234         }      
1235
1236         if (zsstatus & cdmask)  /* fake CARRIER status */
1237                 za->za_flags |= ZAS_CARR_ON;
1238         else
1239                 za->za_flags &= ~ZAS_CARR_ON;
1240         
1241         /*
1242          * we are now gathered here to process some unusual external status
1243          * interrupts.
1244          * any CD events have also been handled and shouldn't be processed
1245          * by the original routine (unless we have a VERY busy port pin)
1246          * some initializations are done here, which could have been done before for
1247          * both code paths but have been avoided for minimum path length to
1248          * the uniq_time routine
1249          */
1250         dname = (char *) 0;
1251         q = za->za_ttycommon.t_readq;
1252
1253         loopcheck = MAXDEPTH;
1254       
1255         /*
1256          * the real thing for everything else ...
1257          */
1258         while (q)
1259         {
1260                 if (q->q_qinfo && q->q_qinfo->qi_minfo)
1261                 {
1262                         dname = q->q_qinfo->qi_minfo->mi_idname;
1263                         if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname))
1264                         {
1265                                 register int (*zsisr) P((struct zscom *));
1266                   
1267                                 /*
1268                                  * back home - phew (hopping along stream queues might
1269                                  * prove dangerous to your health)
1270                                  */
1271                                 if ((zsisr = ((struct savedzsops *)((parsestream_t *)(void *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint))
1272                                         return zsisr(zs);
1273                                 else
1274                                     panic("zs_xsisr: unable to locate original ISR");
1275                   
1276                                 parseprintf(DD_ISR, ("zs_xsisr: non CD event was processed for \"%s\"\n", dname));
1277                                 /*
1278                                  * now back to our program ...
1279                                  */
1280                                 return 0;
1281                         }
1282                 }
1283
1284                 q = q->q_next;
1285
1286                 if (!loopcheck--)
1287                 {
1288                         panic("zs_xsisr: STREAMS Queue corrupted - non CD event");
1289                 }
1290         }
1291
1292         /*
1293          * last resort - shouldn't even come here as it indicates
1294          * corrupted TTY structures
1295          */
1296         printf("zs_zsisr: looking for \"%s\" - found \"%s\" - taking EMERGENCY path\n", parseinfo.st_rdinit->qi_minfo->mi_idname, dname ? dname : "-NIL-");
1297       
1298         if (emergencyzs && emergencyzs->zsop_xsint)
1299             emergencyzs->zsop_xsint(zs);
1300         else
1301             panic("zs_xsisr: no emergency ISR handler");
1302         return 0;
1303 }
1304 #endif                          /* sun */
1305
1306 /*
1307  * History:
1308  *
1309  * parsestreams.c,v
1310  * Revision 4.7  1999/11/28 09:13:53  kardel
1311  * RECON_4_0_98F
1312  *
1313  * Revision 4.6  1998/12/20 23:45:31  kardel
1314  * fix types and warnings
1315  *
1316  * Revision 4.5  1998/11/15 21:23:38  kardel
1317  * ntp_memset() replicated in Sun kernel files
1318  *
1319  * Revision 4.4  1998/06/13 12:15:59  kardel
1320  * superfluous variable removed
1321  *
1322  * Revision 4.3  1998/06/12 15:23:08  kardel
1323  * fix prototypes
1324  * adjust for ansi2knr
1325  *
1326  * Revision 4.2  1998/05/24 18:16:22  kardel
1327  * moved copy of shadow status to the beginning
1328  *
1329  * Revision 4.1  1998/05/24 09:38:47  kardel
1330  * streams initiated iopps calls (M_xHANGUP) are now consistent with the
1331  * respective calls from zs_xsisr()
1332  * simulation of CARRIER status to avoid unecessary M_xHANGUP messages
1333  *
1334  * Revision 4.0  1998/04/10 19:45:38  kardel
1335  * Start 4.0 release version numbering
1336  *
1337  * from V3 3.37 log info deleted 1998/04/11 kardel
1338  */