PageRenderTime 73ms CodeModel.GetById 15ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/ntp/libparse/parsesolaris.c

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