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