PageRenderTime 100ms CodeModel.GetById 43ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/ntp/libparse/parsestreams.c

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