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