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