154359Sroberto/*
2182007Sroberto * /src/NTP/ntp4-dev/libparse/parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A
354359Sroberto *
4182007Sroberto * parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A
554359Sroberto *
654359Sroberto * STREAMS module for reference clocks
754359Sroberto * (SunOS4.x)
854359Sroberto *
9182007Sroberto * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
10182007Sroberto * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany
1154359Sroberto *
12182007Sroberto * Redistribution and use in source and binary forms, with or without
13182007Sroberto * modification, are permitted provided that the following conditions
14182007Sroberto * are met:
15182007Sroberto * 1. Redistributions of source code must retain the above copyright
16182007Sroberto *    notice, this list of conditions and the following disclaimer.
17182007Sroberto * 2. Redistributions in binary form must reproduce the above copyright
18182007Sroberto *    notice, this list of conditions and the following disclaimer in the
19182007Sroberto *    documentation and/or other materials provided with the distribution.
20182007Sroberto * 3. Neither the name of the author nor the names of its contributors
21182007Sroberto *    may be used to endorse or promote products derived from this software
22182007Sroberto *    without specific prior written permission.
23182007Sroberto *
24182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25182007Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26182007Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27182007Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28182007Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29182007Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30182007Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31182007Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32182007Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33182007Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34182007Sroberto * SUCH DAMAGE.
35182007Sroberto *
3654359Sroberto */
3754359Sroberto
3854359Sroberto#define KERNEL			/* MUST */
3954359Sroberto#define VDDRV			/* SHOULD */
4054359Sroberto
4154359Sroberto#ifdef HAVE_CONFIG_H
4254359Sroberto# include "config.h"
4354359Sroberto#endif
4454359Sroberto
4554359Sroberto#ifndef lint
46182007Srobertostatic char rcsid[] = "parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A";
4754359Sroberto#endif
4854359Sroberto
4954359Sroberto#ifndef KERNEL
5054359Sroberto#include "Bletch: MUST COMPILE WITH KERNEL DEFINE"
5154359Sroberto#endif
5254359Sroberto
5354359Sroberto#include <sys/types.h>
5454359Sroberto#include <sys/conf.h>
5554359Sroberto#include <sys/buf.h>
5654359Sroberto#include <sys/param.h>
5754359Sroberto#include <sys/sysmacros.h>
5854359Sroberto#include <sys/time.h>
5954359Sroberto#include <sundev/mbvar.h>
6054359Sroberto#include <sun/autoconf.h>
6154359Sroberto#include <sys/stream.h>
6254359Sroberto#include <sys/stropts.h>
6354359Sroberto#include <sys/dir.h>
6454359Sroberto#include <sys/signal.h>
6554359Sroberto#include <sys/termios.h>
6654359Sroberto#include <sys/termio.h>
6754359Sroberto#include <sys/ttold.h>
6854359Sroberto#include <sys/user.h>
6954359Sroberto#include <sys/tty.h>
7054359Sroberto
7154359Sroberto#ifdef VDDRV
7254359Sroberto#include <sun/vddrv.h>
7354359Sroberto#endif
7454359Sroberto
7554359Sroberto#include "ntp_stdlib.h"
7654359Sroberto#include "ntp_fp.h"
7754359Sroberto/*
7854359Sroberto * just make checking compilers more silent
7954359Sroberto */
8054359Srobertoextern int printf      P((const char *, ...));
8154359Srobertoextern int putctl1     P((queue_t *, int, int));
8254359Srobertoextern int canput      P((queue_t *));
8354359Srobertoextern void putbq      P((queue_t *, mblk_t *));
8454359Srobertoextern void freeb      P((mblk_t *));
8554359Srobertoextern void qreply     P((queue_t *, mblk_t *));
8654359Srobertoextern void freemsg    P((mblk_t *));
8754359Srobertoextern void panic      P((const char *, ...));
8854359Srobertoextern void usec_delay P((int));
8954359Sroberto
9054359Sroberto#include "parse.h"
9154359Sroberto#include "sys/parsestreams.h"
9254359Sroberto
9354359Sroberto/*
9454359Sroberto * use microtime instead of uniqtime if advised to
9554359Sroberto */
9654359Sroberto#ifdef MICROTIME
9754359Sroberto#define uniqtime microtime
9854359Sroberto#endif
9954359Sroberto
10054359Sroberto#ifdef VDDRV
10154359Srobertostatic unsigned int parsebusy = 0;
10254359Sroberto
10354359Sroberto/*--------------- loadable driver section -----------------------------*/
10454359Sroberto
10554359Srobertoextern struct streamtab parseinfo;
10654359Sroberto
10754359Sroberto
10854359Sroberto#ifdef PPS_SYNC
10954359Srobertostatic char mnam[] = "PARSEPPS     ";	/* name this baby - keep room for revision number */
11054359Sroberto#else
11154359Srobertostatic char mnam[] = "PARSE        ";	/* name this baby - keep room for revision number */
11254359Sroberto#endif
11354359Srobertostruct vdldrv parsesync_vd =
11454359Sroberto{
11554359Sroberto	VDMAGIC_PSEUDO,		/* nothing like a real driver - a STREAMS module */
11654359Sroberto	mnam,
11754359Sroberto};
11854359Sroberto
11954359Sroberto/*
12054359Sroberto * strings support usually not in kernel
12154359Sroberto */
12254359Srobertostatic int
12354359SrobertoStrlen(
12454359Sroberto	register const char *s
12554359Sroberto	)
12654359Sroberto{
12754359Sroberto	register int c;
12854359Sroberto
12954359Sroberto	c = 0;
13054359Sroberto	if (s)
13154359Sroberto	{
13254359Sroberto		while (*s++)
13354359Sroberto		{
13454359Sroberto			c++;
13554359Sroberto		}
13654359Sroberto	}
13754359Sroberto	return c;
13854359Sroberto}
13954359Sroberto
14054359Srobertostatic void
14154359SrobertoStrncpy(
14254359Sroberto	register char *t,
14354359Sroberto	register char *s,
14454359Sroberto	register int   c
14554359Sroberto	)
14654359Sroberto{
14754359Sroberto	if (s && t)
14854359Sroberto	{
14954359Sroberto		while ((c-- > 0) && (*t++ = *s++))
15054359Sroberto		    ;
15154359Sroberto	}
15254359Sroberto}
15354359Sroberto
15454359Srobertostatic int
15554359SrobertoStrcmp(
15654359Sroberto	register const char *s,
15754359Sroberto	register const char *t
15854359Sroberto	)
15954359Sroberto{
16054359Sroberto	register int c = 0;
16154359Sroberto
16254359Sroberto	if (!s || !t || (s == t))
16354359Sroberto	{
16454359Sroberto		return 0;
16554359Sroberto	}
16654359Sroberto
16754359Sroberto	while (!(c = *s++ - *t++) && *s && *t)
16854359Sroberto	    /* empty loop */;
16954359Sroberto
17054359Sroberto	return c;
17154359Sroberto}
17254359Sroberto
17354359Srobertostatic int
17454359SrobertoStrncmp(
17554359Sroberto	register char *s,
17654359Sroberto	register char *t,
17754359Sroberto	register int n
17854359Sroberto	)
17954359Sroberto{
18054359Sroberto	register int c = 0;
18154359Sroberto
18254359Sroberto	if (!s || !t || (s == t))
18354359Sroberto	{
18454359Sroberto		return 0;
18554359Sroberto	}
18654359Sroberto
18754359Sroberto	while (n-- && !(c = *s++ - *t++) && *s && *t)
18854359Sroberto	    /* empty loop */;
18954359Sroberto
19054359Sroberto	return c;
19154359Sroberto}
19254359Sroberto
19354359Srobertovoid
19454359Srobertontp_memset(
19554359Sroberto	char *a,
19654359Sroberto	int x,
19754359Sroberto	int c
19854359Sroberto	)
19954359Sroberto{
20054359Sroberto	while (c-- > 0)
20154359Sroberto	    *a++ = x;
20254359Sroberto}
20354359Sroberto
20454359Sroberto/*
20554359Sroberto * driver init routine
20654359Sroberto * since no mechanism gets us into and out of the fmodsw, we have to
20754359Sroberto * do it ourselves
20854359Sroberto */
20954359Sroberto/*ARGSUSED*/
21054359Srobertoint
21154359Srobertoxxxinit(
21254359Sroberto	unsigned int fc,
21354359Sroberto	struct vddrv *vdp,
21454359Sroberto	addr_t vdin,
21554359Sroberto	struct vdstat *vds
21654359Sroberto	)
21754359Sroberto{
21854359Sroberto	extern struct fmodsw fmodsw[];
21954359Sroberto	extern int fmodcnt;
22054359Sroberto
22154359Sroberto	struct fmodsw *fm    = fmodsw;
22254359Sroberto	struct fmodsw *fmend = &fmodsw[fmodcnt];
22354359Sroberto	struct fmodsw *ifm   = (struct fmodsw *)0;
22454359Sroberto	char *mname          = parseinfo.st_rdinit->qi_minfo->mi_idname;
22554359Sroberto
22654359Sroberto	switch (fc)
22754359Sroberto	{
22854359Sroberto	    case VDLOAD:
22954359Sroberto		vdp->vdd_vdtab = (struct vdlinkage *)&parsesync_vd;
23054359Sroberto		/*
23154359Sroberto		 * now, jog along fmodsw scanning for an empty slot
23254359Sroberto		 * and deposit our name there
23354359Sroberto		 */
23454359Sroberto		while (fm <= fmend)
23554359Sroberto		{
23654359Sroberto	  if (!Strncmp(fm->f_name, mname, FMNAMESZ))
23754359Sroberto			{
23854359Sroberto				printf("vddrinit[%s]: STREAMS module already loaded.\n", mname);
23954359Sroberto				return(EBUSY);
24054359Sroberto			}
24154359Sroberto			else
24254359Sroberto			    if ((ifm == (struct fmodsw *)0) &&
24354359Sroberto				(fm->f_name[0] == '\0') &&
24454359Sroberto				(fm->f_str == (struct streamtab *)0))
24554359Sroberto			    {
24654359Sroberto				    /*
24754359Sroberto				     * got one - so move in
24854359Sroberto				     */
24954359Sroberto				    ifm = fm;
25054359Sroberto				    break;
25154359Sroberto			    }
25254359Sroberto			fm++;
25354359Sroberto		}
25454359Sroberto
25554359Sroberto		if (ifm == (struct fmodsw *)0)
25654359Sroberto		{
25754359Sroberto			printf("vddrinit[%s]: no slot free for STREAMS module\n", mname);
25854359Sroberto			return (ENOSPC);
25954359Sroberto		}
26054359Sroberto		else
26154359Sroberto		{
26256746Sroberto			static char revision[] = "4.7";
26354359Sroberto			char *s, *S, *t;
26454359Sroberto
26554359Sroberto			s = rcsid;		/* NOOP - keep compilers happy */
26654359Sroberto
26754359Sroberto			Strncpy(ifm->f_name, mname, FMNAMESZ);
26854359Sroberto			ifm->f_name[FMNAMESZ] = '\0';
26954359Sroberto			ifm->f_str = &parseinfo;
27054359Sroberto			/*
27154359Sroberto			 * copy RCS revision into Drv_name
27254359Sroberto			 *
27354359Sroberto			 * are we forcing RCS here to do things it was not built for ?
27454359Sroberto			 */
27554359Sroberto			s = revision;
27654359Sroberto			if (*s == '$')
27754359Sroberto			{
27854359Sroberto				/*
27954359Sroberto				 * skip "$Revision: "
28054359Sroberto				 * if present. - not necessary on a -kv co (cvs export)
28154359Sroberto				 */
28254359Sroberto				while (*s && (*s != ' '))
28354359Sroberto				{
28454359Sroberto					s++;
28554359Sroberto				}
28654359Sroberto				if (*s == ' ') s++;
28754359Sroberto			}
28854359Sroberto
28954359Sroberto			t = parsesync_vd.Drv_name;
29054359Sroberto			while (*t && (*t != ' '))
29154359Sroberto			{
29254359Sroberto				t++;
29354359Sroberto			}
29454359Sroberto			if (*t == ' ') t++;
29554359Sroberto
29654359Sroberto			S = s;
29754359Sroberto			while (*S && (((*S >= '0') && (*S <= '9')) || (*S == '.')))
29854359Sroberto			{
29954359Sroberto				S++;
30054359Sroberto			}
30154359Sroberto
30254359Sroberto			if (*s && *t && (S > s))
30354359Sroberto			{
30454359Sroberto				if (Strlen(t) >= (S - s))
30554359Sroberto				{
30654359Sroberto					(void) Strncpy(t, s, S - s);
30754359Sroberto				}
30854359Sroberto			}
30954359Sroberto			return (0);
31054359Sroberto		}
31154359Sroberto		break;
31254359Sroberto
31354359Sroberto	    case VDUNLOAD:
31454359Sroberto		if (parsebusy > 0)
31554359Sroberto		{
31654359Sroberto			printf("vddrinit[%s]: STREAMS module has still %d instances active.\n", mname, parsebusy);
31754359Sroberto			return (EBUSY);
31854359Sroberto		}
31954359Sroberto		else
32054359Sroberto		{
32154359Sroberto			while (fm <= fmend)
32254359Sroberto			{
32354359Sroberto				if (!Strncmp(fm->f_name, mname, FMNAMESZ))
32454359Sroberto				{
32554359Sroberto					/*
32654359Sroberto					 * got it - kill entry
32754359Sroberto					 */
32854359Sroberto					fm->f_name[0] = '\0';
32954359Sroberto					fm->f_str = (struct streamtab *)0;
33054359Sroberto					fm++;
33154359Sroberto
33254359Sroberto					break;
33354359Sroberto				}
33454359Sroberto				fm++;
33554359Sroberto			}
33654359Sroberto			if (fm > fmend)
33754359Sroberto			{
33854359Sroberto				printf("vddrinit[%s]: cannot find entry for STREAMS module\n", mname);
33954359Sroberto				return (ENXIO);
34054359Sroberto			}
34154359Sroberto			else
34254359Sroberto			    return (0);
34354359Sroberto		}
34454359Sroberto
34554359Sroberto
34654359Sroberto	    case VDSTAT:
34754359Sroberto		return (0);
34854359Sroberto
34954359Sroberto	    default:
35054359Sroberto		return (EIO);
35154359Sroberto
35254359Sroberto	}
35354359Sroberto	return EIO;
35454359Sroberto}
35554359Sroberto
35654359Sroberto#endif
35754359Sroberto
35854359Sroberto/*--------------- stream module definition ----------------------------*/
35954359Sroberto
36054359Srobertostatic int parseopen  P((queue_t *, dev_t, int, int));
36154359Srobertostatic int parseclose P((queue_t *, int));
36254359Srobertostatic int parsewput  P((queue_t *, mblk_t *));
36354359Srobertostatic int parserput  P((queue_t *, mblk_t *));
36454359Srobertostatic int parsersvc  P((queue_t *));
36554359Sroberto
36654359Srobertostatic char mn[] = "parse";
36754359Sroberto
36854359Srobertostatic struct module_info driverinfo =
36954359Sroberto{
37054359Sroberto	0,				/* module ID number */
37154359Sroberto	mn,			/* module name */
37254359Sroberto	0,				/* minimum accepted packet size */
37354359Sroberto	INFPSZ,			/* maximum accepted packet size */
37454359Sroberto	1,				/* high water mark - flow control */
37554359Sroberto	0				/* low water mark - flow control */
37654359Sroberto};
37754359Sroberto
37854359Srobertostatic struct qinit rinit =	/* read queue definition */
37954359Sroberto{
38054359Sroberto	parserput,			/* put procedure */
38154359Sroberto	parsersvc,			/* service procedure */
38254359Sroberto	parseopen,			/* open procedure */
38354359Sroberto	parseclose,			/* close procedure */
38454359Sroberto	NULL,				/* admin procedure - NOT USED FOR NOW */
38554359Sroberto	&driverinfo,			/* information structure */
38654359Sroberto	NULL				/* statistics */
38754359Sroberto};
38854359Sroberto
38954359Srobertostatic struct qinit winit =	/* write queue definition */
39054359Sroberto{
39154359Sroberto	parsewput,			/* put procedure */
39254359Sroberto	NULL,				/* service procedure */
39354359Sroberto	NULL,				/* open procedure */
39454359Sroberto	NULL,				/* close procedure */
39554359Sroberto	NULL,				/* admin procedure - NOT USED FOR NOW */
39654359Sroberto	&driverinfo,			/* information structure */
39754359Sroberto	NULL				/* statistics */
39854359Sroberto};
39954359Sroberto
40054359Srobertostruct streamtab parseinfo =	/* stream info element for dpr driver */
40154359Sroberto{
40254359Sroberto	&rinit,			/* read queue */
40354359Sroberto	&winit,			/* write queue */
40454359Sroberto	NULL,				/* read mux */
40554359Sroberto	NULL,				/* write mux */
40654359Sroberto	NULL				/* module auto push */
40754359Sroberto};
40854359Sroberto
40954359Sroberto/*--------------- driver data structures ----------------------------*/
41054359Sroberto
41154359Sroberto/*
41254359Sroberto * we usually have an inverted signal - but you
41354359Sroberto * can change this to suit your needs
41454359Sroberto */
41554359Srobertoint cd_invert = 1;		/* invert status of CD line - PPS support via CD input */
41654359Sroberto
41754359Srobertoint parsedebug = ~0;
41854359Sroberto
41954359Srobertoextern void uniqtime P((struct timeval *));
42054359Sroberto
42154359Sroberto/*--------------- module implementation -----------------------------*/
42254359Sroberto
42354359Sroberto#define TIMEVAL_USADD(_X_, _US_) {\
42454359Sroberto                                   (_X_)->tv_usec += (_US_);\
42554359Sroberto			           if ((_X_)->tv_usec >= 1000000)\
42654359Sroberto                                     {\
42754359Sroberto                                       (_X_)->tv_sec++;\
42854359Sroberto			               (_X_)->tv_usec -= 1000000;\
42954359Sroberto                                     }\
43054359Sroberto				 } while (0)
43154359Sroberto
43254359Srobertostatic int init_linemon P((queue_t *));
43354359Srobertostatic void close_linemon P((queue_t *, queue_t *));
43454359Sroberto
43554359Sroberto#define M_PARSE		0x0001
43654359Sroberto#define M_NOPARSE	0x0002
43754359Sroberto
43854359Srobertostatic int
43954359Srobertosetup_stream(
44054359Sroberto	     queue_t *q,
44154359Sroberto	     int mode
44254359Sroberto	     )
44354359Sroberto{
44454359Sroberto	mblk_t *mp;
44554359Sroberto
44654359Sroberto	mp = allocb(sizeof(struct stroptions), BPRI_MED);
44754359Sroberto	if (mp)
44854359Sroberto	{
44954359Sroberto		struct stroptions *str = (struct stroptions *)(void *)mp->b_rptr;
45054359Sroberto
45154359Sroberto		str->so_flags   = SO_READOPT|SO_HIWAT|SO_LOWAT;
45254359Sroberto		str->so_readopt = (mode == M_PARSE) ? RMSGD : RNORM;
45354359Sroberto		str->so_hiwat   = (mode == M_PARSE) ? sizeof(parsetime_t) : 256;
45454359Sroberto		str->so_lowat   = 0;
45554359Sroberto		mp->b_datap->db_type = M_SETOPTS;
45654359Sroberto		mp->b_wptr += sizeof(struct stroptions);
45754359Sroberto		putnext(q, mp);
45854359Sroberto		return putctl1(WR(q)->q_next, M_CTL, (mode == M_PARSE) ? MC_SERVICEIMM :
45954359Sroberto			       MC_SERVICEDEF);
46054359Sroberto	}
46154359Sroberto	else
46254359Sroberto	{
46354359Sroberto		parseprintf(DD_OPEN,("parse: setup_stream - FAILED - no MEMORY for allocb\n"));
46454359Sroberto		return 0;
46554359Sroberto	}
46654359Sroberto}
46754359Sroberto
46854359Sroberto/*ARGSUSED*/
46954359Srobertostatic int
47054359Srobertoparseopen(
47154359Sroberto	queue_t *q,
47254359Sroberto	dev_t dev,
47354359Sroberto	int flag,
47454359Sroberto	int sflag
47554359Sroberto	)
47654359Sroberto{
47754359Sroberto	register parsestream_t *parse;
47854359Sroberto	static int notice = 0;
47954359Sroberto
48054359Sroberto	parseprintf(DD_OPEN,("parse: OPEN\n"));
48154359Sroberto
48254359Sroberto	if (sflag != MODOPEN)
48354359Sroberto	{			/* open only for modules */
48454359Sroberto		parseprintf(DD_OPEN,("parse: OPEN - FAILED - not MODOPEN\n"));
48554359Sroberto		return OPENFAIL;
48654359Sroberto	}
48754359Sroberto
48854359Sroberto	if (q->q_ptr != (caddr_t)NULL)
48954359Sroberto	{
49054359Sroberto		u.u_error = EBUSY;
49154359Sroberto		parseprintf(DD_OPEN,("parse: OPEN - FAILED - EXCLUSIVE ONLY\n"));
49254359Sroberto		return OPENFAIL;
49354359Sroberto	}
49454359Sroberto
49554359Sroberto#ifdef VDDRV
49654359Sroberto	parsebusy++;
49754359Sroberto#endif
49854359Sroberto
49954359Sroberto	q->q_ptr = (caddr_t)kmem_alloc(sizeof(parsestream_t));
50054359Sroberto	if (q->q_ptr == (caddr_t)0)
50154359Sroberto	{
50254359Sroberto		parseprintf(DD_OPEN,("parse: OPEN - FAILED - no memory\n"));
50354359Sroberto#ifdef VDDRV
50454359Sroberto		parsebusy--;
50554359Sroberto#endif
50654359Sroberto		return OPENFAIL;
50754359Sroberto	}
50854359Sroberto	WR(q)->q_ptr = q->q_ptr;
50954359Sroberto
51054359Sroberto	parse = (parsestream_t *)(void *)q->q_ptr;
51154359Sroberto	bzero((caddr_t)parse, sizeof(*parse));
51254359Sroberto	parse->parse_queue     = q;
51354359Sroberto	parse->parse_status    = PARSE_ENABLE;
51454359Sroberto	parse->parse_ppsclockev.tv.tv_sec  = 0;
51554359Sroberto	parse->parse_ppsclockev.tv.tv_usec = 0;
51654359Sroberto	parse->parse_ppsclockev.serial     = 0;
51754359Sroberto
51854359Sroberto	if (!parse_ioinit(&parse->parse_io))
51954359Sroberto	{
52054359Sroberto		/*
52154359Sroberto		 * ok guys - beat it
52254359Sroberto		 */
52354359Sroberto		kmem_free((caddr_t)parse, sizeof(parsestream_t));
52454359Sroberto#ifdef VDDRV
52554359Sroberto		parsebusy--;
52654359Sroberto#endif
52754359Sroberto		return OPENFAIL;
52854359Sroberto	}
52954359Sroberto
53054359Sroberto	if (setup_stream(q, M_PARSE))
53154359Sroberto	{
53254359Sroberto		(void) init_linemon(q);	/* hook up PPS ISR routines if possible */
53354359Sroberto
53454359Sroberto		parseprintf(DD_OPEN,("parse: OPEN - SUCCEEDED\n"));
53554359Sroberto
53654359Sroberto		/*
53754359Sroberto		 * I know that you know the delete key, but you didn't write this
53854359Sroberto		 * code, did you ? - So, keep the message in here.
53954359Sroberto		 */
54054359Sroberto		if (!notice)
54154359Sroberto		{
54254359Sroberto#ifdef VDDRV
543182007Sroberto			printf("%s: Copyright (C) 1991-2005, Frank Kardel\n", parsesync_vd.Drv_name);
54454359Sroberto#else
545182007Sroberto			printf("%s: Copyright (C) 1991-2005, Frank Kardel\n", "parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A");
54654359Sroberto#endif
54754359Sroberto			notice = 1;
54854359Sroberto		}
54954359Sroberto
55054359Sroberto		return MODOPEN;
55154359Sroberto	}
55254359Sroberto	else
55354359Sroberto	{
55454359Sroberto		kmem_free((caddr_t)parse, sizeof(parsestream_t));
55554359Sroberto
55654359Sroberto#ifdef VDDRV
55754359Sroberto		parsebusy--;
55854359Sroberto#endif
55954359Sroberto		return OPENFAIL;
56054359Sroberto	}
56154359Sroberto}
56254359Sroberto
56354359Sroberto/*ARGSUSED*/
56454359Srobertostatic int
56554359Srobertoparseclose(
56654359Sroberto	queue_t *q,
56754359Sroberto	int flags
56854359Sroberto	)
56954359Sroberto{
57054359Sroberto	register parsestream_t *parse = (parsestream_t *)(void *)q->q_ptr;
57154359Sroberto	register unsigned long s;
57254359Sroberto
57354359Sroberto	parseprintf(DD_CLOSE,("parse: CLOSE\n"));
57454359Sroberto
57554359Sroberto	s = splhigh();
57654359Sroberto
57754359Sroberto	if (parse->parse_dqueue)
57854359Sroberto	    close_linemon(parse->parse_dqueue, q);
57954359Sroberto	parse->parse_dqueue = (queue_t *)0;
58054359Sroberto
58154359Sroberto	(void) splx(s);
58254359Sroberto
58354359Sroberto	parse_ioend(&parse->parse_io);
58454359Sroberto
58554359Sroberto	kmem_free((caddr_t)parse, sizeof(parsestream_t));
58654359Sroberto
58754359Sroberto	q->q_ptr = (caddr_t)NULL;
58854359Sroberto	WR(q)->q_ptr = (caddr_t)NULL;
58954359Sroberto
59054359Sroberto#ifdef VDDRV
59154359Sroberto	parsebusy--;
59254359Sroberto#endif
59354359Sroberto	return 0;
59454359Sroberto}
59554359Sroberto
59654359Sroberto/*
59754359Sroberto * move unrecognized stuff upward
59854359Sroberto */
59954359Srobertostatic int
60054359Srobertoparsersvc(
60154359Sroberto	queue_t *q
60254359Sroberto	)
60354359Sroberto{
60454359Sroberto	mblk_t *mp;
60554359Sroberto
60654359Sroberto	while ((mp = getq(q)))
60754359Sroberto	{
60854359Sroberto		if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
60954359Sroberto		{
61054359Sroberto			putnext(q, mp);
61154359Sroberto			parseprintf(DD_RSVC,("parse: RSVC - putnext\n"));
61254359Sroberto		}
61354359Sroberto		else
61454359Sroberto		{
61554359Sroberto			putbq(q, mp);
61654359Sroberto			parseprintf(DD_RSVC,("parse: RSVC - flow control wait\n"));
61754359Sroberto			break;
61854359Sroberto		}
61954359Sroberto	}
62054359Sroberto	return 0;
62154359Sroberto}
62254359Sroberto
62354359Sroberto/*
62454359Sroberto * do ioctls and
62554359Sroberto * send stuff down - dont care about
62654359Sroberto * flow control
62754359Sroberto */
62854359Srobertostatic int
62954359Srobertoparsewput(
63054359Sroberto	queue_t *q,
63154359Sroberto	register mblk_t *mp
63254359Sroberto	)
63354359Sroberto{
63454359Sroberto	register int ok = 1;
63554359Sroberto	register mblk_t *datap;
63654359Sroberto	register struct iocblk *iocp;
63754359Sroberto	parsestream_t         *parse = (parsestream_t *)(void *)q->q_ptr;
63854359Sroberto
63954359Sroberto	parseprintf(DD_WPUT,("parse: parsewput\n"));
64054359Sroberto
64154359Sroberto	switch (mp->b_datap->db_type)
64254359Sroberto	{
64354359Sroberto	    default:
64454359Sroberto		putnext(q, mp);
64554359Sroberto		break;
64654359Sroberto
64754359Sroberto	    case M_IOCTL:
64854359Sroberto		    iocp = (struct iocblk *)(void *)mp->b_rptr;
64954359Sroberto		switch (iocp->ioc_cmd)
65054359Sroberto		{
65154359Sroberto		    default:
65254359Sroberto			parseprintf(DD_WPUT,("parse: parsewput - forward M_IOCTL\n"));
65354359Sroberto			putnext(q, mp);
65454359Sroberto			break;
65554359Sroberto
65654359Sroberto		    case CIOGETEV:
65754359Sroberto			/*
65854359Sroberto			 * taken from Craig Leres ppsclock module (and modified)
65954359Sroberto			 */
66054359Sroberto			datap = allocb(sizeof(struct ppsclockev), BPRI_MED);
66154359Sroberto			if (datap == NULL || mp->b_cont)
66254359Sroberto			{
66354359Sroberto				mp->b_datap->db_type = M_IOCNAK;
66454359Sroberto				iocp->ioc_error = (datap == NULL) ? ENOMEM : EINVAL;
66554359Sroberto				if (datap != NULL)
66654359Sroberto				    freeb(datap);
66754359Sroberto				qreply(q, mp);
66854359Sroberto				break;
66954359Sroberto			}
67054359Sroberto
67154359Sroberto			mp->b_cont = datap;
67254359Sroberto			*(struct ppsclockev *)(void *)datap->b_wptr = parse->parse_ppsclockev;
67354359Sroberto			datap->b_wptr +=
67454359Sroberto				sizeof(struct ppsclockev) / sizeof(*datap->b_wptr);
67554359Sroberto			mp->b_datap->db_type = M_IOCACK;
67654359Sroberto			iocp->ioc_count = sizeof(struct ppsclockev);
67754359Sroberto			qreply(q, mp);
67854359Sroberto			break;
67954359Sroberto
68054359Sroberto		    case PARSEIOC_ENABLE:
68154359Sroberto		    case PARSEIOC_DISABLE:
68254359Sroberto			    {
68354359Sroberto				    parse->parse_status = (parse->parse_status & (unsigned)~PARSE_ENABLE) |
68454359Sroberto					    (iocp->ioc_cmd == PARSEIOC_ENABLE) ?
68554359Sroberto					    PARSE_ENABLE : 0;
68654359Sroberto				    if (!setup_stream(RD(q), (parse->parse_status & PARSE_ENABLE) ?
68754359Sroberto						      M_PARSE : M_NOPARSE))
68854359Sroberto				    {
68954359Sroberto					    mp->b_datap->db_type = M_IOCNAK;
69054359Sroberto				    }
69154359Sroberto				    else
69254359Sroberto				    {
69354359Sroberto					    mp->b_datap->db_type = M_IOCACK;
69454359Sroberto				    }
69554359Sroberto				    qreply(q, mp);
69654359Sroberto				    break;
69754359Sroberto			    }
69854359Sroberto
69954359Sroberto		    case PARSEIOC_TIMECODE:
70054359Sroberto		    case PARSEIOC_SETFMT:
70154359Sroberto		    case PARSEIOC_GETFMT:
70254359Sroberto		    case PARSEIOC_SETCS:
70354359Sroberto			if (iocp->ioc_count == sizeof(parsectl_t))
70454359Sroberto			{
70554359Sroberto				parsectl_t *dct = (parsectl_t *)(void *)mp->b_cont->b_rptr;
70654359Sroberto
70754359Sroberto				switch (iocp->ioc_cmd)
70854359Sroberto				{
70954359Sroberto				    case PARSEIOC_TIMECODE:
71054359Sroberto					parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_TIMECODE\n"));
71154359Sroberto					ok = parse_timecode(dct, &parse->parse_io);
71254359Sroberto					break;
71354359Sroberto
71454359Sroberto				    case PARSEIOC_SETFMT:
71554359Sroberto					parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETFMT\n"));
71654359Sroberto					ok = parse_setfmt(dct, &parse->parse_io);
71754359Sroberto					break;
71854359Sroberto
71954359Sroberto				    case PARSEIOC_GETFMT:
72054359Sroberto					parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_GETFMT\n"));
72154359Sroberto					ok = parse_getfmt(dct, &parse->parse_io);
72254359Sroberto					break;
72354359Sroberto
72454359Sroberto				    case PARSEIOC_SETCS:
72554359Sroberto					parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETCS\n"));
72654359Sroberto					ok = parse_setcs(dct, &parse->parse_io);
72754359Sroberto					break;
72854359Sroberto				}
72954359Sroberto				mp->b_datap->db_type = ok ? M_IOCACK : M_IOCNAK;
73054359Sroberto			}
73154359Sroberto			else
73254359Sroberto			{
73354359Sroberto				mp->b_datap->db_type = M_IOCNAK;
73454359Sroberto			}
73554359Sroberto			parseprintf(DD_WPUT,("parse: parsewput qreply - %s\n", (mp->b_datap->db_type == M_IOCNAK) ? "M_IOCNAK" : "M_IOCACK"));
73654359Sroberto			qreply(q, mp);
73754359Sroberto			break;
73854359Sroberto		}
73954359Sroberto	}
74054359Sroberto	return 0;
74154359Sroberto}
74254359Sroberto
74354359Sroberto/*
74454359Sroberto * read characters from streams buffers
74554359Sroberto */
74654359Srobertostatic unsigned long
74754359Srobertordchar(
74854359Sroberto       register mblk_t **mp
74954359Sroberto       )
75054359Sroberto{
75154359Sroberto	while (*mp != (mblk_t *)NULL)
75254359Sroberto	{
75354359Sroberto		if ((*mp)->b_wptr - (*mp)->b_rptr)
75454359Sroberto		{
75554359Sroberto			return (unsigned long)(*(unsigned char *)((*mp)->b_rptr++));
75654359Sroberto		}
75754359Sroberto		else
75854359Sroberto		{
75954359Sroberto			register mblk_t *mmp = *mp;
76054359Sroberto
76154359Sroberto			*mp = (*mp)->b_cont;
76254359Sroberto			freeb(mmp);
76354359Sroberto		}
76454359Sroberto	}
76554359Sroberto	return (unsigned)~0;
76654359Sroberto}
76754359Sroberto
76854359Sroberto/*
76954359Sroberto * convert incoming data
77054359Sroberto */
77154359Srobertostatic int
77254359Srobertoparserput(
77354359Sroberto	queue_t *q,
77454359Sroberto	mblk_t *mp
77554359Sroberto	)
77654359Sroberto{
77754359Sroberto	unsigned char type;
77854359Sroberto
77954359Sroberto	switch (type = mp->b_datap->db_type)
78054359Sroberto	{
78154359Sroberto	    default:
78254359Sroberto		/*
78354359Sroberto		 * anything we don't know will be put on queue
78454359Sroberto		 * the service routine will move it to the next one
78554359Sroberto		 */
78654359Sroberto		parseprintf(DD_RPUT,("parse: parserput - forward type 0x%x\n", type));
78754359Sroberto		if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
78854359Sroberto		{
78954359Sroberto			putnext(q, mp);
79054359Sroberto		}
79154359Sroberto		else
79254359Sroberto		    putq(q, mp);
79354359Sroberto		break;
79454359Sroberto
79554359Sroberto	    case M_BREAK:
79654359Sroberto	    case M_DATA:
79754359Sroberto		    {
79854359Sroberto			    register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr;
79954359Sroberto			    register mblk_t *nmp;
80054359Sroberto			    register unsigned long ch;
80154359Sroberto			    timestamp_t ctime;
80254359Sroberto
80354359Sroberto			    /*
80454359Sroberto			     * get time on packet delivery
80554359Sroberto			     */
80654359Sroberto			    uniqtime(&ctime.tv);
80754359Sroberto
80854359Sroberto			    if (!(parse->parse_status & PARSE_ENABLE))
80954359Sroberto			    {
81054359Sroberto				    parseprintf(DD_RPUT,("parse: parserput - parser disabled - forward type 0x%x\n", type));
81154359Sroberto				    if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
81254359Sroberto				    {
81354359Sroberto					    putnext(q, mp);
81454359Sroberto				    }
81554359Sroberto				    else
81654359Sroberto					putq(q, mp);
81754359Sroberto			    }
81854359Sroberto			    else
81954359Sroberto			    {
82054359Sroberto				    parseprintf(DD_RPUT,("parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK"));
82154359Sroberto
82254359Sroberto				    if (type == M_DATA)
82354359Sroberto				    {
82454359Sroberto					    /*
82554359Sroberto					     * parse packet looking for start an end characters
82654359Sroberto					     */
82754359Sroberto					    while (mp != (mblk_t *)NULL)
82854359Sroberto					    {
82954359Sroberto						    ch = rdchar(&mp);
83054359Sroberto						    if (ch != ~0 && parse_ioread(&parse->parse_io, (unsigned int)ch, &ctime))
83154359Sroberto						    {
83254359Sroberto							    /*
83354359Sroberto							     * up up and away (hopefully ...)
83454359Sroberto							     * don't press it if resources are tight or nobody wants it
83554359Sroberto							     */
83654359Sroberto							    nmp = (mblk_t *)NULL;
83754359Sroberto							    if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
83854359Sroberto							    {
83954359Sroberto								    bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
84054359Sroberto								    nmp->b_wptr += sizeof(parsetime_t);
84154359Sroberto								    putnext(parse->parse_queue, nmp);
84254359Sroberto							    }
84354359Sroberto							    else
84454359Sroberto								if (nmp) freemsg(nmp);
84554359Sroberto							    parse_iodone(&parse->parse_io);
84654359Sroberto						    }
84754359Sroberto					    }
84854359Sroberto				    }
84954359Sroberto				    else
85054359Sroberto				    {
85154359Sroberto					    if (parse_ioread(&parse->parse_io, (unsigned int)0, &ctime))
85254359Sroberto					    {
85354359Sroberto						    /*
85454359Sroberto						     * up up and away (hopefully ...)
85554359Sroberto						     * don't press it if resources are tight or nobody wants it
85654359Sroberto						     */
85754359Sroberto						    nmp = (mblk_t *)NULL;
85854359Sroberto						    if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
85954359Sroberto						    {
86054359Sroberto							    bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
86154359Sroberto							    nmp->b_wptr += sizeof(parsetime_t);
86254359Sroberto							    putnext(parse->parse_queue, nmp);
86354359Sroberto						    }
86454359Sroberto						    else
86554359Sroberto							if (nmp) freemsg(nmp);
86654359Sroberto						    parse_iodone(&parse->parse_io);
86754359Sroberto					    }
86854359Sroberto					    freemsg(mp);
86954359Sroberto				    }
87054359Sroberto				    break;
87154359Sroberto			    }
87254359Sroberto		    }
87354359Sroberto
87454359Sroberto		    /*
87554359Sroberto		     * CD PPS support for non direct ISR hack
87654359Sroberto		     */
87754359Sroberto	    case M_HANGUP:
87854359Sroberto	    case M_UNHANGUP:
87954359Sroberto		    {
88054359Sroberto			    register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr;
88154359Sroberto			    timestamp_t ctime;
88254359Sroberto			    register mblk_t *nmp;
88354359Sroberto			    register int status = cd_invert ^ (type == M_UNHANGUP);
88454359Sroberto
88554359Sroberto			    uniqtime(&ctime.tv);
88654359Sroberto
88754359Sroberto			    parseprintf(DD_RPUT,("parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN"));
88854359Sroberto
88954359Sroberto			    if ((parse->parse_status & PARSE_ENABLE) &&
89054359Sroberto				parse_iopps(&parse->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &ctime))
89154359Sroberto			    {
89254359Sroberto				    nmp = (mblk_t *)NULL;
89354359Sroberto				    if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
89454359Sroberto				    {
89554359Sroberto					    bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
89654359Sroberto					    nmp->b_wptr += sizeof(parsetime_t);
89754359Sroberto					    putnext(parse->parse_queue, nmp);
89854359Sroberto				    }
89954359Sroberto				    else
90054359Sroberto					if (nmp) freemsg(nmp);
90154359Sroberto				    parse_iodone(&parse->parse_io);
90254359Sroberto				    freemsg(mp);
90354359Sroberto			    }
90454359Sroberto			    else
90554359Sroberto				if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
90654359Sroberto				{
90754359Sroberto					putnext(q, mp);
90854359Sroberto				}
90954359Sroberto				else
91054359Sroberto				    putq(q, mp);
91154359Sroberto
91254359Sroberto			    if (status)
91354359Sroberto			    {
91454359Sroberto				    parse->parse_ppsclockev.tv = ctime.tv;
91554359Sroberto				    ++(parse->parse_ppsclockev.serial);
91654359Sroberto			    }
91754359Sroberto		    }
91854359Sroberto	}
91954359Sroberto	return 0;
92054359Sroberto}
92154359Sroberto
92254359Srobertostatic int  init_zs_linemon  P((queue_t *, queue_t *));	/* handle line monitor for "zs" driver */
92354359Srobertostatic void close_zs_linemon P((queue_t *, queue_t *));
92454359Sroberto
92554359Sroberto/*-------------------- CD isr status monitor ---------------*/
92654359Sroberto
92754359Srobertostatic int
92854359Srobertoinit_linemon(
92954359Sroberto	register queue_t *q
93054359Sroberto	)
93154359Sroberto{
93254359Sroberto	register queue_t *dq;
93354359Sroberto
93454359Sroberto	dq = WR(q);
93554359Sroberto	/*
93654359Sroberto	 * we ARE doing very bad things down here (basically stealing ISR
93754359Sroberto	 * hooks)
93854359Sroberto	 *
93954359Sroberto	 * so we chase down the STREAMS stack searching for the driver
94054359Sroberto	 * and if this is a known driver we insert our ISR routine for
94154359Sroberto	 * status changes in to the ExternalStatus handling hook
94254359Sroberto	 */
94354359Sroberto	while (dq->q_next)
94454359Sroberto	{
94554359Sroberto		dq = dq->q_next;		/* skip down to driver */
94654359Sroberto	}
94754359Sroberto
94854359Sroberto	/*
94954359Sroberto	 * find appropriate driver dependent routine
95054359Sroberto	 */
95154359Sroberto	if (dq->q_qinfo && dq->q_qinfo->qi_minfo)
95254359Sroberto	{
95354359Sroberto		register char *dname = dq->q_qinfo->qi_minfo->mi_idname;
95454359Sroberto
95554359Sroberto		parseprintf(DD_INSTALL, ("init_linemon: driver is \"%s\"\n", dname));
95654359Sroberto
95754359Sroberto#ifdef sun
95854359Sroberto		if (dname && !Strcmp(dname, "zs"))
95954359Sroberto		{
96054359Sroberto			return init_zs_linemon(dq, q);
96154359Sroberto		}
96254359Sroberto		else
96354359Sroberto#endif
96454359Sroberto		{
96554359Sroberto			parseprintf(DD_INSTALL, ("init_linemon: driver \"%s\" not suitable for CD monitoring\n", dname));
96654359Sroberto			return 0;
96754359Sroberto		}
96854359Sroberto	}
96954359Sroberto	parseprintf(DD_INSTALL, ("init_linemon: cannot find driver\n"));
97054359Sroberto	return 0;
97154359Sroberto}
97254359Sroberto
97354359Srobertostatic void
97454359Srobertoclose_linemon(
97554359Sroberto	register queue_t *q,
97654359Sroberto	register queue_t *my_q
97754359Sroberto	)
97854359Sroberto{
97954359Sroberto	/*
98054359Sroberto	 * find appropriate driver dependent routine
98154359Sroberto	 */
98254359Sroberto	if (q->q_qinfo && q->q_qinfo->qi_minfo)
98354359Sroberto	{
98454359Sroberto		register char *dname = q->q_qinfo->qi_minfo->mi_idname;
98554359Sroberto
98654359Sroberto#ifdef sun
98754359Sroberto		if (dname && !Strcmp(dname, "zs"))
98854359Sroberto		{
98954359Sroberto			close_zs_linemon(q, my_q);
99054359Sroberto			return;
99154359Sroberto		}
99254359Sroberto		parseprintf(DD_INSTALL, ("close_linemon: cannot find driver close routine for \"%s\"\n", dname));
99354359Sroberto#endif
99454359Sroberto	}
99554359Sroberto	parseprintf(DD_INSTALL, ("close_linemon: cannot find driver name\n"));
99654359Sroberto}
99754359Sroberto
99854359Sroberto#ifdef sun
99954359Sroberto
100054359Sroberto#include <sundev/zsreg.h>
100154359Sroberto#include <sundev/zscom.h>
100254359Sroberto#include <sundev/zsvar.h>
100354359Sroberto
100454359Srobertostatic unsigned long cdmask  = ZSRR0_CD;
100554359Sroberto
100654359Srobertostruct savedzsops
100754359Sroberto{
100854359Sroberto	struct zsops  zsops;
100954359Sroberto	struct zsops *oldzsops;
101054359Sroberto};
101154359Sroberto
101254359Srobertostruct zsops   *emergencyzs;
101354359Srobertoextern void zsopinit   P((struct zscom *, struct zsops *));
101454359Srobertostatic int  zs_xsisr   P((struct zscom *));	/* zs external status interupt handler */
101554359Sroberto
101654359Srobertostatic int
101754359Srobertoinit_zs_linemon(
101854359Sroberto	register queue_t *q,
101954359Sroberto	register queue_t *my_q
102054359Sroberto	)
102154359Sroberto{
102254359Sroberto	register struct zscom *zs;
102354359Sroberto	register struct savedzsops *szs;
102454359Sroberto	register parsestream_t  *parsestream = (parsestream_t *)(void *)my_q->q_ptr;
102554359Sroberto	/*
102654359Sroberto	 * we expect the zsaline pointer in the q_data pointer
102754359Sroberto	 * from there on we insert our on EXTERNAL/STATUS ISR routine
102854359Sroberto	 * into the interrupt path, before the standard handler
102954359Sroberto	 */
103054359Sroberto	zs = ((struct zsaline *)(void *)q->q_ptr)->za_common;
103154359Sroberto	if (!zs)
103254359Sroberto	{
103354359Sroberto		/*
103454359Sroberto		 * well - not found on startup - just say no (shouldn't happen though)
103554359Sroberto		 */
103654359Sroberto		return 0;
103754359Sroberto	}
103854359Sroberto	else
103954359Sroberto	{
104054359Sroberto		unsigned long s;
104154359Sroberto
104254359Sroberto		/*
104354359Sroberto		 * we do a direct replacement, in case others fiddle also
104454359Sroberto		 * if somebody else grabs our hook and we disconnect
104554359Sroberto		 * we are in DEEP trouble - panic is likely to be next, sorry
104654359Sroberto		 */
104754359Sroberto		szs = (struct savedzsops *)(void *)kmem_alloc(sizeof(struct savedzsops));
104854359Sroberto
104954359Sroberto		if (szs == (struct savedzsops *)0)
105054359Sroberto		{
105154359Sroberto			parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor NOT installed - no memory\n"));
105254359Sroberto
105354359Sroberto			return 0;
105454359Sroberto		}
105554359Sroberto		else
105654359Sroberto		{
105754359Sroberto			parsestream->parse_data   = (void *)szs;
105854359Sroberto
105954359Sroberto			s = splhigh();
106054359Sroberto
106154359Sroberto			parsestream->parse_dqueue = q; /* remember driver */
106254359Sroberto
106354359Sroberto			szs->zsops            = *zs->zs_ops;
106454359Sroberto			szs->zsops.zsop_xsint = zs_xsisr; /* place our bastard */
106554359Sroberto			szs->oldzsops         = zs->zs_ops;
106654359Sroberto			emergencyzs           = zs->zs_ops;
106754359Sroberto
106854359Sroberto			zsopinit(zs, &szs->zsops); /* hook it up */
106954359Sroberto
107054359Sroberto			(void) splx(s);
107154359Sroberto
107254359Sroberto			parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor installed\n"));
107354359Sroberto
107454359Sroberto			return 1;
107554359Sroberto		}
107654359Sroberto	}
107754359Sroberto}
107854359Sroberto
107954359Sroberto/*
108054359Sroberto * unregister our ISR routine - must call under splhigh()
108154359Sroberto */
108254359Srobertostatic void
108354359Srobertoclose_zs_linemon(
108454359Sroberto	register queue_t *q,
108554359Sroberto	register queue_t *my_q
108654359Sroberto	)
108754359Sroberto{
108854359Sroberto	register struct zscom *zs;
108954359Sroberto	register parsestream_t  *parsestream = (parsestream_t *)(void *)my_q->q_ptr;
109054359Sroberto
109154359Sroberto	zs = ((struct zsaline *)(void *)q->q_ptr)->za_common;
109254359Sroberto	if (!zs)
109354359Sroberto	{
109454359Sroberto		/*
109554359Sroberto		 * well - not found on startup - just say no (shouldn't happen though)
109654359Sroberto		 */
109754359Sroberto		return;
109854359Sroberto	}
109954359Sroberto	else
110054359Sroberto	{
110154359Sroberto		register struct savedzsops *szs = (struct savedzsops *)parsestream->parse_data;
110254359Sroberto
110354359Sroberto		zsopinit(zs, szs->oldzsops); /* reset to previous handler functions */
110454359Sroberto
110554359Sroberto		kmem_free((caddr_t)szs, sizeof (struct savedzsops));
110654359Sroberto
110754359Sroberto		parseprintf(DD_INSTALL, ("close_zs_linemon: CD monitor deleted\n"));
110854359Sroberto		return;
110954359Sroberto	}
111054359Sroberto}
111154359Sroberto
111254359Sroberto#define MAXDEPTH 50		/* maximum allowed stream crawl */
111354359Sroberto
111454359Sroberto#ifdef PPS_SYNC
111554359Srobertoextern void hardpps P((struct timeval *, long));
111654359Sroberto#ifdef PPS_NEW
111754359Srobertoextern struct timeval timestamp;
111854359Sroberto#else
111954359Srobertoextern struct timeval pps_time;
112054359Sroberto#endif
112154359Sroberto#endif
112254359Sroberto
112354359Sroberto/*
112454359Sroberto * take external status interrupt (only CD interests us)
112554359Sroberto */
112654359Srobertostatic int
112754359Srobertozs_xsisr(
112854359Sroberto	 struct zscom *zs
112954359Sroberto	)
113054359Sroberto{
113154359Sroberto	register struct zsaline *za = (struct zsaline *)(void *)zs->zs_priv;
113254359Sroberto	register struct zscc_device *zsaddr = zs->zs_addr;
113354359Sroberto	register queue_t *q;
113454359Sroberto	register unsigned char zsstatus;
113554359Sroberto	register int loopcheck;
113654359Sroberto	register char *dname;
113754359Sroberto#ifdef PPS_SYNC
113854359Sroberto	register unsigned int s;
113954359Sroberto	register long usec;
114054359Sroberto#endif
114154359Sroberto
114254359Sroberto	/*
114354359Sroberto	 * pick up current state
114454359Sroberto	 */
114554359Sroberto	zsstatus = zsaddr->zscc_control;
114654359Sroberto
114754359Sroberto	if ((za->za_rr0 ^ zsstatus) & (cdmask))
114854359Sroberto	{
114954359Sroberto		timestamp_t cdevent;
115054359Sroberto		register int status;
115154359Sroberto
115254359Sroberto		za->za_rr0 = (za->za_rr0 & ~(cdmask)) | (zsstatus & (cdmask));
115354359Sroberto
115454359Sroberto#ifdef PPS_SYNC
115554359Sroberto		s = splclock();
115654359Sroberto#ifdef PPS_NEW
115754359Sroberto		usec = timestamp.tv_usec;
115854359Sroberto#else
115954359Sroberto		usec = pps_time.tv_usec;
116054359Sroberto#endif
116154359Sroberto#endif
116254359Sroberto		/*
116354359Sroberto		 * time stamp
116454359Sroberto		 */
116554359Sroberto		uniqtime(&cdevent.tv);
116654359Sroberto
116754359Sroberto#ifdef PPS_SYNC
116854359Sroberto		(void)splx(s);
116954359Sroberto#endif
117054359Sroberto
117154359Sroberto		/*
117254359Sroberto		 * logical state
117354359Sroberto		 */
117454359Sroberto		status = cd_invert ? (zsstatus & cdmask) == 0 : (zsstatus & cdmask) != 0;
117554359Sroberto
117654359Sroberto#ifdef PPS_SYNC
117754359Sroberto		if (status)
117854359Sroberto		{
117954359Sroberto			usec = cdevent.tv.tv_usec - usec;
118054359Sroberto			if (usec < 0)
118154359Sroberto			    usec += 1000000;
118254359Sroberto
118354359Sroberto			hardpps(&cdevent.tv, usec);
118454359Sroberto		}
118554359Sroberto#endif
118654359Sroberto
118754359Sroberto		q = za->za_ttycommon.t_readq;
118854359Sroberto
118954359Sroberto		/*
119054359Sroberto		 * ok - now the hard part - find ourself
119154359Sroberto		 */
119254359Sroberto		loopcheck = MAXDEPTH;
119354359Sroberto
119454359Sroberto		while (q)
119554359Sroberto		{
119654359Sroberto			if (q->q_qinfo && q->q_qinfo->qi_minfo)
119754359Sroberto			{
119854359Sroberto				dname = q->q_qinfo->qi_minfo->mi_idname;
119954359Sroberto
120054359Sroberto				if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname))
120154359Sroberto				{
120254359Sroberto					/*
120354359Sroberto					 * back home - phew (hopping along stream queues might
120454359Sroberto					 * prove dangerous to your health)
120554359Sroberto					 */
120654359Sroberto
120754359Sroberto					if ((((parsestream_t *)(void *)q->q_ptr)->parse_status & PARSE_ENABLE) &&
120854359Sroberto					    parse_iopps(&((parsestream_t *)(void *)q->q_ptr)->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &cdevent))
120954359Sroberto					{
121054359Sroberto						/*
121154359Sroberto						 * XXX - currently we do not pass up the message, as
121254359Sroberto						 * we should.
121354359Sroberto						 * for a correct behaviour wee need to block out
121454359Sroberto						 * processing until parse_iodone has been posted via
121554359Sroberto						 * a softcall-ed routine which does the message pass-up
121654359Sroberto						 * right now PPS information relies on input being
121754359Sroberto						 * received
121854359Sroberto						 */
121954359Sroberto						parse_iodone(&((parsestream_t *)(void *)q->q_ptr)->parse_io);
122054359Sroberto					}
122154359Sroberto
122254359Sroberto					if (status)
122354359Sroberto					{
122454359Sroberto						((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.tv = cdevent.tv;
122554359Sroberto						++(((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.serial);
122654359Sroberto					}
122754359Sroberto
122854359Sroberto					parseprintf(DD_ISR, ("zs_xsisr: CD event %s has been posted for \"%s\"\n", status ? "ONE" : "ZERO", dname));
122954359Sroberto					break;
123054359Sroberto				}
123154359Sroberto			}
123254359Sroberto
123354359Sroberto			q = q->q_next;
123454359Sroberto
123554359Sroberto			if (!loopcheck--)
123654359Sroberto			{
123754359Sroberto				panic("zs_xsisr: STREAMS Queue corrupted - CD event");
123854359Sroberto			}
123954359Sroberto		}
124054359Sroberto
124154359Sroberto		/*
124254359Sroberto		 * only pretend that CD has been handled
124354359Sroberto		 */
124454359Sroberto		ZSDELAY(2);
124554359Sroberto
124654359Sroberto		if (!((za->za_rr0 ^ zsstatus) & ~(cdmask)))
124754359Sroberto		{
124854359Sroberto			/*
124954359Sroberto			 * all done - kill status indication and return
125054359Sroberto			 */
125154359Sroberto			zsaddr->zscc_control = ZSWR0_RESET_STATUS; /* might kill other conditions here */
125254359Sroberto			return 0;
125354359Sroberto		}
125454359Sroberto	}
125554359Sroberto
125654359Sroberto	if (zsstatus & cdmask)	/* fake CARRIER status */
125754359Sroberto		za->za_flags |= ZAS_CARR_ON;
125854359Sroberto	else
125954359Sroberto		za->za_flags &= ~ZAS_CARR_ON;
126054359Sroberto
126154359Sroberto	/*
126254359Sroberto	 * we are now gathered here to process some unusual external status
126354359Sroberto	 * interrupts.
126454359Sroberto	 * any CD events have also been handled and shouldn't be processed
126554359Sroberto	 * by the original routine (unless we have a VERY busy port pin)
126654359Sroberto	 * some initializations are done here, which could have been done before for
126754359Sroberto	 * both code paths but have been avoided for minimum path length to
126854359Sroberto	 * the uniq_time routine
126954359Sroberto	 */
127054359Sroberto	dname = (char *) 0;
127154359Sroberto	q = za->za_ttycommon.t_readq;
127254359Sroberto
127354359Sroberto	loopcheck = MAXDEPTH;
127454359Sroberto
127554359Sroberto	/*
127654359Sroberto	 * the real thing for everything else ...
127754359Sroberto	 */
127854359Sroberto	while (q)
127954359Sroberto	{
128054359Sroberto		if (q->q_qinfo && q->q_qinfo->qi_minfo)
128154359Sroberto		{
128254359Sroberto			dname = q->q_qinfo->qi_minfo->mi_idname;
128354359Sroberto			if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname))
128454359Sroberto			{
128554359Sroberto				register int (*zsisr) P((struct zscom *));
128654359Sroberto
128754359Sroberto				/*
128854359Sroberto				 * back home - phew (hopping along stream queues might
128954359Sroberto				 * prove dangerous to your health)
129054359Sroberto				 */
129154359Sroberto				if ((zsisr = ((struct savedzsops *)((parsestream_t *)(void *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint))
129254359Sroberto					return zsisr(zs);
129354359Sroberto				else
129454359Sroberto				    panic("zs_xsisr: unable to locate original ISR");
129554359Sroberto
129654359Sroberto				parseprintf(DD_ISR, ("zs_xsisr: non CD event was processed for \"%s\"\n", dname));
129754359Sroberto				/*
129854359Sroberto				 * now back to our program ...
129954359Sroberto				 */
130054359Sroberto				return 0;
130154359Sroberto			}
130254359Sroberto		}
130354359Sroberto
130454359Sroberto		q = q->q_next;
130554359Sroberto
130654359Sroberto		if (!loopcheck--)
130754359Sroberto		{
130854359Sroberto			panic("zs_xsisr: STREAMS Queue corrupted - non CD event");
130954359Sroberto		}
131054359Sroberto	}
131154359Sroberto
131254359Sroberto	/*
131354359Sroberto	 * last resort - shouldn't even come here as it indicates
131454359Sroberto	 * corrupted TTY structures
131554359Sroberto	 */
131654359Sroberto	printf("zs_zsisr: looking for \"%s\" - found \"%s\" - taking EMERGENCY path\n", parseinfo.st_rdinit->qi_minfo->mi_idname, dname ? dname : "-NIL-");
131754359Sroberto
131854359Sroberto	if (emergencyzs && emergencyzs->zsop_xsint)
131954359Sroberto	    emergencyzs->zsop_xsint(zs);
132054359Sroberto	else
132154359Sroberto	    panic("zs_xsisr: no emergency ISR handler");
132254359Sroberto	return 0;
132354359Sroberto}
132454359Sroberto#endif				/* sun */
132554359Sroberto
132654359Sroberto/*
132754359Sroberto * History:
132854359Sroberto *
132954359Sroberto * parsestreams.c,v
1330182007Sroberto * Revision 4.11  2005/04/16 17:32:10  kardel
1331182007Sroberto * update copyright
1332182007Sroberto *
1333182007Sroberto * Revision 4.10  2004/11/14 16:06:08  kardel
1334182007Sroberto * update Id tags
1335182007Sroberto *
1336182007Sroberto * Revision 4.9  2004/11/14 15:29:41  kardel
1337182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style
1338182007Sroberto *
133956746Sroberto * Revision 4.7  1999/11/28 09:13:53  kardel
134056746Sroberto * RECON_4_0_98F
134156746Sroberto *
134254359Sroberto * Revision 4.6  1998/12/20 23:45:31  kardel
134354359Sroberto * fix types and warnings
134454359Sroberto *
134554359Sroberto * Revision 4.5  1998/11/15 21:23:38  kardel
134654359Sroberto * ntp_memset() replicated in Sun kernel files
134754359Sroberto *
134854359Sroberto * Revision 4.4  1998/06/13 12:15:59  kardel
134954359Sroberto * superfluous variable removed
135054359Sroberto *
135154359Sroberto * Revision 4.3  1998/06/12 15:23:08  kardel
135254359Sroberto * fix prototypes
135354359Sroberto * adjust for ansi2knr
135454359Sroberto *
135554359Sroberto * Revision 4.2  1998/05/24 18:16:22  kardel
135654359Sroberto * moved copy of shadow status to the beginning
135754359Sroberto *
135854359Sroberto * Revision 4.1  1998/05/24 09:38:47  kardel
135954359Sroberto * streams initiated iopps calls (M_xHANGUP) are now consistent with the
136054359Sroberto * respective calls from zs_xsisr()
136154359Sroberto * simulation of CARRIER status to avoid unecessary M_xHANGUP messages
136254359Sroberto *
136354359Sroberto * Revision 4.0  1998/04/10 19:45:38  kardel
136454359Sroberto * Start 4.0 release version numbering
136554359Sroberto *
136654359Sroberto * from V3 3.37 log info deleted 1998/04/11 kardel
136754359Sroberto */
1368