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