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