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