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