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