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