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