Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / libparse / parsestreams.c
blob0dbf7c0e0ae8ca80695be9c1d53df52cb9919008
1 /* $NetBSD: parsestreams.c,v 1.2 2003/12/04 16:23:37 drochner Exp $ */
3 /*
4 * /src/NTP/ntp4-dev/libparse/parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A
5 *
6 * parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A
8 * STREAMS module for reference clocks
9 * (SunOS4.x)
11 * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
12 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the author nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
40 #define KERNEL /* MUST */
41 #define VDDRV /* SHOULD */
43 #ifdef HAVE_CONFIG_H
44 # include "config.h"
45 #endif
47 #ifndef lint
48 static char rcsid[] = "parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A";
49 #endif
51 #ifndef KERNEL
52 #include "Bletch: MUST COMPILE WITH KERNEL DEFINE"
53 #endif
55 #include <sys/types.h>
56 #include <sys/conf.h>
57 #include <sys/buf.h>
58 #include <sys/param.h>
59 #include <sys/sysmacros.h>
60 #include <sys/time.h>
61 #include <sundev/mbvar.h>
62 #include <sun/autoconf.h>
63 #include <sys/stream.h>
64 #include <sys/stropts.h>
65 #include <sys/dir.h>
66 #include <sys/signal.h>
67 #include <sys/termios.h>
68 #include <sys/termio.h>
69 #include <sys/ttold.h>
70 #include <sys/user.h>
71 #include <sys/tty.h>
73 #ifdef VDDRV
74 #include <sun/vddrv.h>
75 #endif
77 #include "ntp_stdlib.h"
78 #include "ntp_fp.h"
80 * just make checking compilers more silent
82 extern int printf P((const char *, ...));
83 extern int putctl1 P((queue_t *, int, int));
84 extern int canput P((queue_t *));
85 extern void putbq P((queue_t *, mblk_t *));
86 extern void freeb P((mblk_t *));
87 extern void qreply P((queue_t *, mblk_t *));
88 extern void freemsg P((mblk_t *));
89 extern void panic P((const char *, ...));
90 extern void usec_delay P((int));
92 #include "parse.h"
93 #include "sys/parsestreams.h"
96 * use microtime instead of uniqtime if advised to
98 #ifdef MICROTIME
99 #define uniqtime microtime
100 #endif
102 #ifdef VDDRV
103 static unsigned int parsebusy = 0;
105 /*--------------- loadable driver section -----------------------------*/
107 extern struct streamtab parseinfo;
110 #ifdef PPS_SYNC
111 static char mnam[] = "PARSEPPS "; /* name this baby - keep room for revision number */
112 #else
113 static char mnam[] = "PARSE "; /* name this baby - keep room for revision number */
114 #endif
115 struct vdldrv parsesync_vd =
117 VDMAGIC_PSEUDO, /* nothing like a real driver - a STREAMS module */
118 mnam,
122 * strings support usually not in kernel
124 static int
125 Strlen(
126 register const char *s
129 register int c;
131 c = 0;
132 if (s)
134 while (*s++)
136 c++;
139 return c;
142 static void
143 Strncpy(
144 register char *t,
145 register char *s,
146 register int c
149 if (s && t)
151 while ((c-- > 0) && (*t++ = *s++))
156 static int
157 Strcmp(
158 register const char *s,
159 register const char *t
162 register int c = 0;
164 if (!s || !t || (s == t))
166 return 0;
169 while (!(c = *s++ - *t++) && *s && *t)
170 /* empty loop */;
172 return c;
175 static int
176 Strncmp(
177 register char *s,
178 register char *t,
179 register int n
182 register int c = 0;
184 if (!s || !t || (s == t))
186 return 0;
189 while (n-- && !(c = *s++ - *t++) && *s && *t)
190 /* empty loop */;
192 return c;
195 void
196 ntp_memset(
197 char *a,
198 int x,
199 int c
202 while (c-- > 0)
203 *a++ = x;
207 * driver init routine
208 * since no mechanism gets us into and out of the fmodsw, we have to
209 * do it ourselves
211 /*ARGSUSED*/
213 xxxinit(
214 unsigned int fc,
215 struct vddrv *vdp,
216 addr_t vdin,
217 struct vdstat *vds
220 extern struct fmodsw fmodsw[];
221 extern int fmodcnt;
223 struct fmodsw *fm = fmodsw;
224 struct fmodsw *fmend = &fmodsw[fmodcnt];
225 struct fmodsw *ifm = (struct fmodsw *)0;
226 char *mname = parseinfo.st_rdinit->qi_minfo->mi_idname;
228 switch (fc)
230 case VDLOAD:
231 vdp->vdd_vdtab = (struct vdlinkage *)&parsesync_vd;
233 * now, jog along fmodsw scanning for an empty slot
234 * and deposit our name there
236 while (fm <= fmend)
238 if (!Strncmp(fm->f_name, mname, FMNAMESZ))
240 printf("vddrinit[%s]: STREAMS module already loaded.\n", mname);
241 return(EBUSY);
243 else
244 if ((ifm == (struct fmodsw *)0) &&
245 (fm->f_name[0] == '\0') &&
246 (fm->f_str == (struct streamtab *)0))
249 * got one - so move in
251 ifm = fm;
252 break;
254 fm++;
257 if (ifm == (struct fmodsw *)0)
259 printf("vddrinit[%s]: no slot free for STREAMS module\n", mname);
260 return (ENOSPC);
262 else
264 static char revision[] = "4.7";
265 char *s, *S, *t;
267 s = rcsid; /* NOOP - keep compilers happy */
269 Strncpy(ifm->f_name, mname, FMNAMESZ);
270 ifm->f_name[FMNAMESZ] = '\0';
271 ifm->f_str = &parseinfo;
273 * copy RCS revision into Drv_name
275 * are we forcing RCS here to do things it was not built for ?
277 s = revision;
278 if (*s == '$')
281 * skip "$Revision: "
282 * if present. - not necessary on a -kv co (cvs export)
284 while (*s && (*s != ' '))
286 s++;
288 if (*s == ' ') s++;
291 t = parsesync_vd.Drv_name;
292 while (*t && (*t != ' '))
294 t++;
296 if (*t == ' ') t++;
298 S = s;
299 while (*S && (((*S >= '0') && (*S <= '9')) || (*S == '.')))
301 S++;
304 if (*s && *t && (S > s))
306 if (Strlen(t) >= (S - s))
308 (void) Strncpy(t, s, S - s);
311 return (0);
313 break;
315 case VDUNLOAD:
316 if (parsebusy > 0)
318 printf("vddrinit[%s]: STREAMS module has still %d instances active.\n", mname, parsebusy);
319 return (EBUSY);
321 else
323 while (fm <= fmend)
325 if (!Strncmp(fm->f_name, mname, FMNAMESZ))
328 * got it - kill entry
330 fm->f_name[0] = '\0';
331 fm->f_str = (struct streamtab *)0;
332 fm++;
334 break;
336 fm++;
338 if (fm > fmend)
340 printf("vddrinit[%s]: cannot find entry for STREAMS module\n", mname);
341 return (ENXIO);
343 else
344 return (0);
348 case VDSTAT:
349 return (0);
351 default:
352 return (EIO);
355 return EIO;
358 #endif
360 /*--------------- stream module definition ----------------------------*/
362 static int parseopen P((queue_t *, dev_t, int, int));
363 static int parseclose P((queue_t *, int));
364 static int parsewput P((queue_t *, mblk_t *));
365 static int parserput P((queue_t *, mblk_t *));
366 static int parsersvc P((queue_t *));
368 static char mn[] = "parse";
370 static struct module_info driverinfo =
372 0, /* module ID number */
373 mn, /* module name */
374 0, /* minimum accepted packet size */
375 INFPSZ, /* maximum accepted packet size */
376 1, /* high water mark - flow control */
377 0 /* low water mark - flow control */
380 static struct qinit rinit = /* read queue definition */
382 parserput, /* put procedure */
383 parsersvc, /* service procedure */
384 parseopen, /* open procedure */
385 parseclose, /* close procedure */
386 NULL, /* admin procedure - NOT USED FOR NOW */
387 &driverinfo, /* information structure */
388 NULL /* statistics */
391 static struct qinit winit = /* write queue definition */
393 parsewput, /* put procedure */
394 NULL, /* service procedure */
395 NULL, /* open procedure */
396 NULL, /* close procedure */
397 NULL, /* admin procedure - NOT USED FOR NOW */
398 &driverinfo, /* information structure */
399 NULL /* statistics */
402 struct streamtab parseinfo = /* stream info element for dpr driver */
404 &rinit, /* read queue */
405 &winit, /* write queue */
406 NULL, /* read mux */
407 NULL, /* write mux */
408 NULL /* module auto push */
411 /*--------------- driver data structures ----------------------------*/
414 * we usually have an inverted signal - but you
415 * can change this to suit your needs
417 int cd_invert = 1; /* invert status of CD line - PPS support via CD input */
419 int parsedebug = ~0;
421 extern void uniqtime P((struct timeval *));
423 /*--------------- module implementation -----------------------------*/
425 #define TIMEVAL_USADD(_X_, _US_) {\
426 (_X_)->tv_usec += (_US_);\
427 if ((_X_)->tv_usec >= 1000000)\
429 (_X_)->tv_sec++;\
430 (_X_)->tv_usec -= 1000000;\
432 } while (0)
434 static int init_linemon P((queue_t *));
435 static void close_linemon P((queue_t *, queue_t *));
437 #define M_PARSE 0x0001
438 #define M_NOPARSE 0x0002
440 static int
441 setup_stream(
442 queue_t *q,
443 int mode
446 mblk_t *mp;
448 mp = allocb(sizeof(struct stroptions), BPRI_MED);
449 if (mp)
451 struct stroptions *str = (struct stroptions *)(void *)mp->b_rptr;
453 str->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT;
454 str->so_readopt = (mode == M_PARSE) ? RMSGD : RNORM;
455 str->so_hiwat = (mode == M_PARSE) ? sizeof(parsetime_t) : 256;
456 str->so_lowat = 0;
457 mp->b_datap->db_type = M_SETOPTS;
458 mp->b_wptr += sizeof(struct stroptions);
459 putnext(q, mp);
460 return putctl1(WR(q)->q_next, M_CTL, (mode == M_PARSE) ? MC_SERVICEIMM :
461 MC_SERVICEDEF);
463 else
465 parseprintf(DD_OPEN,("parse: setup_stream - FAILED - no MEMORY for allocb\n"));
466 return 0;
470 /*ARGSUSED*/
471 static int
472 parseopen(
473 queue_t *q,
474 dev_t dev,
475 int flag,
476 int sflag
479 register parsestream_t *parse;
480 static int notice = 0;
482 parseprintf(DD_OPEN,("parse: OPEN\n"));
484 if (sflag != MODOPEN)
485 { /* open only for modules */
486 parseprintf(DD_OPEN,("parse: OPEN - FAILED - not MODOPEN\n"));
487 return OPENFAIL;
490 if (q->q_ptr != (caddr_t)NULL)
492 u.u_error = EBUSY;
493 parseprintf(DD_OPEN,("parse: OPEN - FAILED - EXCLUSIVE ONLY\n"));
494 return OPENFAIL;
497 #ifdef VDDRV
498 parsebusy++;
499 #endif
501 q->q_ptr = (caddr_t)kmem_alloc(sizeof(parsestream_t));
502 if (q->q_ptr == (caddr_t)0)
504 parseprintf(DD_OPEN,("parse: OPEN - FAILED - no memory\n"));
505 #ifdef VDDRV
506 parsebusy--;
507 #endif
508 return OPENFAIL;
510 WR(q)->q_ptr = q->q_ptr;
512 parse = (parsestream_t *)(void *)q->q_ptr;
513 bzero((caddr_t)parse, sizeof(*parse));
514 parse->parse_queue = q;
515 parse->parse_status = PARSE_ENABLE;
516 parse->parse_ppsclockev.tv.tv_sec = 0;
517 parse->parse_ppsclockev.tv.tv_usec = 0;
518 parse->parse_ppsclockev.serial = 0;
520 if (!parse_ioinit(&parse->parse_io))
523 * ok guys - beat it
525 kmem_free((caddr_t)parse, sizeof(parsestream_t));
526 #ifdef VDDRV
527 parsebusy--;
528 #endif
529 return OPENFAIL;
532 if (setup_stream(q, M_PARSE))
534 (void) init_linemon(q); /* hook up PPS ISR routines if possible */
536 parseprintf(DD_OPEN,("parse: OPEN - SUCCEEDED\n"));
539 * I know that you know the delete key, but you didn't write this
540 * code, did you ? - So, keep the message in here.
542 if (!notice)
544 #ifdef VDDRV
545 printf("%s: Copyright (C) 1991-2005, Frank Kardel\n", parsesync_vd.Drv_name);
546 #else
547 printf("%s: Copyright (C) 1991-2005, Frank Kardel\n", "parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A");
548 #endif
549 notice = 1;
552 return MODOPEN;
554 else
556 kmem_free((caddr_t)parse, sizeof(parsestream_t));
558 #ifdef VDDRV
559 parsebusy--;
560 #endif
561 return OPENFAIL;
565 /*ARGSUSED*/
566 static int
567 parseclose(
568 queue_t *q,
569 int flags
572 register parsestream_t *parse = (parsestream_t *)(void *)q->q_ptr;
573 register unsigned long s;
575 parseprintf(DD_CLOSE,("parse: CLOSE\n"));
577 s = splhigh();
579 if (parse->parse_dqueue)
580 close_linemon(parse->parse_dqueue, q);
581 parse->parse_dqueue = (queue_t *)0;
583 (void) splx(s);
585 parse_ioend(&parse->parse_io);
587 kmem_free((caddr_t)parse, sizeof(parsestream_t));
589 q->q_ptr = (caddr_t)NULL;
590 WR(q)->q_ptr = (caddr_t)NULL;
592 #ifdef VDDRV
593 parsebusy--;
594 #endif
595 return 0;
599 * move unrecognized stuff upward
601 static int
602 parsersvc(
603 queue_t *q
606 mblk_t *mp;
608 while ((mp = getq(q)))
610 if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
612 putnext(q, mp);
613 parseprintf(DD_RSVC,("parse: RSVC - putnext\n"));
615 else
617 putbq(q, mp);
618 parseprintf(DD_RSVC,("parse: RSVC - flow control wait\n"));
619 break;
622 return 0;
626 * do ioctls and
627 * send stuff down - dont care about
628 * flow control
630 static int
631 parsewput(
632 queue_t *q,
633 register mblk_t *mp
636 register int ok = 1;
637 register mblk_t *datap;
638 register struct iocblk *iocp;
639 parsestream_t *parse = (parsestream_t *)(void *)q->q_ptr;
641 parseprintf(DD_WPUT,("parse: parsewput\n"));
643 switch (mp->b_datap->db_type)
645 default:
646 putnext(q, mp);
647 break;
649 case M_IOCTL:
650 iocp = (struct iocblk *)(void *)mp->b_rptr;
651 switch (iocp->ioc_cmd)
653 default:
654 parseprintf(DD_WPUT,("parse: parsewput - forward M_IOCTL\n"));
655 putnext(q, mp);
656 break;
658 case CIOGETEV:
660 * taken from Craig Leres ppsclock module (and modified)
662 datap = allocb(sizeof(struct ppsclockev), BPRI_MED);
663 if (datap == NULL || mp->b_cont)
665 mp->b_datap->db_type = M_IOCNAK;
666 iocp->ioc_error = (datap == NULL) ? ENOMEM : EINVAL;
667 if (datap != NULL)
668 freeb(datap);
669 qreply(q, mp);
670 break;
673 mp->b_cont = datap;
674 *(struct ppsclockev *)(void *)datap->b_wptr = parse->parse_ppsclockev;
675 datap->b_wptr +=
676 sizeof(struct ppsclockev) / sizeof(*datap->b_wptr);
677 mp->b_datap->db_type = M_IOCACK;
678 iocp->ioc_count = sizeof(struct ppsclockev);
679 qreply(q, mp);
680 break;
682 case PARSEIOC_ENABLE:
683 case PARSEIOC_DISABLE:
685 parse->parse_status = (parse->parse_status & (unsigned)~PARSE_ENABLE) |
686 (iocp->ioc_cmd == PARSEIOC_ENABLE) ?
687 PARSE_ENABLE : 0;
688 if (!setup_stream(RD(q), (parse->parse_status & PARSE_ENABLE) ?
689 M_PARSE : M_NOPARSE))
691 mp->b_datap->db_type = M_IOCNAK;
693 else
695 mp->b_datap->db_type = M_IOCACK;
697 qreply(q, mp);
698 break;
701 case PARSEIOC_TIMECODE:
702 case PARSEIOC_SETFMT:
703 case PARSEIOC_GETFMT:
704 case PARSEIOC_SETCS:
705 if (iocp->ioc_count == sizeof(parsectl_t))
707 parsectl_t *dct = (parsectl_t *)(void *)mp->b_cont->b_rptr;
709 switch (iocp->ioc_cmd)
711 case PARSEIOC_TIMECODE:
712 parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_TIMECODE\n"));
713 ok = parse_timecode(dct, &parse->parse_io);
714 break;
716 case PARSEIOC_SETFMT:
717 parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETFMT\n"));
718 ok = parse_setfmt(dct, &parse->parse_io);
719 break;
721 case PARSEIOC_GETFMT:
722 parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_GETFMT\n"));
723 ok = parse_getfmt(dct, &parse->parse_io);
724 break;
726 case PARSEIOC_SETCS:
727 parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETCS\n"));
728 ok = parse_setcs(dct, &parse->parse_io);
729 break;
731 mp->b_datap->db_type = ok ? M_IOCACK : M_IOCNAK;
733 else
735 mp->b_datap->db_type = M_IOCNAK;
737 parseprintf(DD_WPUT,("parse: parsewput qreply - %s\n", (mp->b_datap->db_type == M_IOCNAK) ? "M_IOCNAK" : "M_IOCACK"));
738 qreply(q, mp);
739 break;
742 return 0;
746 * read characters from streams buffers
748 static unsigned long
749 rdchar(
750 register mblk_t **mp
753 while (*mp != (mblk_t *)NULL)
755 if ((*mp)->b_wptr - (*mp)->b_rptr)
757 return (unsigned long)(*(unsigned char *)((*mp)->b_rptr++));
759 else
761 register mblk_t *mmp = *mp;
763 *mp = (*mp)->b_cont;
764 freeb(mmp);
767 return (unsigned)~0;
771 * convert incoming data
773 static int
774 parserput(
775 queue_t *q,
776 mblk_t *mp
779 unsigned char type;
781 switch (type = mp->b_datap->db_type)
783 default:
785 * anything we don't know will be put on queue
786 * the service routine will move it to the next one
788 parseprintf(DD_RPUT,("parse: parserput - forward type 0x%x\n", type));
789 if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
791 putnext(q, mp);
793 else
794 putq(q, mp);
795 break;
797 case M_BREAK:
798 case M_DATA:
800 register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr;
801 register mblk_t *nmp;
802 register unsigned long ch;
803 timestamp_t ctime;
806 * get time on packet delivery
808 uniqtime(&ctime.tv);
810 if (!(parse->parse_status & PARSE_ENABLE))
812 parseprintf(DD_RPUT,("parse: parserput - parser disabled - forward type 0x%x\n", type));
813 if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
815 putnext(q, mp);
817 else
818 putq(q, mp);
820 else
822 parseprintf(DD_RPUT,("parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK"));
824 if (type == M_DATA)
827 * parse packet looking for start an end characters
829 while (mp != (mblk_t *)NULL)
831 ch = rdchar(&mp);
832 if (ch != ~0 && parse_ioread(&parse->parse_io, (unsigned int)ch, &ctime))
835 * up up and away (hopefully ...)
836 * don't press it if resources are tight or nobody wants it
838 nmp = (mblk_t *)NULL;
839 if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
841 bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
842 nmp->b_wptr += sizeof(parsetime_t);
843 putnext(parse->parse_queue, nmp);
845 else
846 if (nmp) freemsg(nmp);
847 parse_iodone(&parse->parse_io);
851 else
853 if (parse_ioread(&parse->parse_io, (unsigned int)0, &ctime))
856 * up up and away (hopefully ...)
857 * don't press it if resources are tight or nobody wants it
859 nmp = (mblk_t *)NULL;
860 if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
862 bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
863 nmp->b_wptr += sizeof(parsetime_t);
864 putnext(parse->parse_queue, nmp);
866 else
867 if (nmp) freemsg(nmp);
868 parse_iodone(&parse->parse_io);
870 freemsg(mp);
872 break;
877 * CD PPS support for non direct ISR hack
879 case M_HANGUP:
880 case M_UNHANGUP:
882 register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr;
883 timestamp_t ctime;
884 register mblk_t *nmp;
885 register int status = cd_invert ^ (type == M_UNHANGUP);
887 uniqtime(&ctime.tv);
889 parseprintf(DD_RPUT,("parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN"));
891 if ((parse->parse_status & PARSE_ENABLE) &&
892 parse_iopps(&parse->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &ctime))
894 nmp = (mblk_t *)NULL;
895 if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
897 bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
898 nmp->b_wptr += sizeof(parsetime_t);
899 putnext(parse->parse_queue, nmp);
901 else
902 if (nmp) freemsg(nmp);
903 parse_iodone(&parse->parse_io);
904 freemsg(mp);
906 else
907 if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
909 putnext(q, mp);
911 else
912 putq(q, mp);
914 if (status)
916 parse->parse_ppsclockev.tv = ctime.tv;
917 ++(parse->parse_ppsclockev.serial);
921 return 0;
924 static int init_zs_linemon P((queue_t *, queue_t *)); /* handle line monitor for "zs" driver */
925 static void close_zs_linemon P((queue_t *, queue_t *));
927 /*-------------------- CD isr status monitor ---------------*/
929 static int
930 init_linemon(
931 register queue_t *q
934 register queue_t *dq;
936 dq = WR(q);
938 * we ARE doing very bad things down here (basically stealing ISR
939 * hooks)
941 * so we chase down the STREAMS stack searching for the driver
942 * and if this is a known driver we insert our ISR routine for
943 * status changes in to the ExternalStatus handling hook
945 while (dq->q_next)
947 dq = dq->q_next; /* skip down to driver */
951 * find appropriate driver dependent routine
953 if (dq->q_qinfo && dq->q_qinfo->qi_minfo)
955 register char *dname = dq->q_qinfo->qi_minfo->mi_idname;
957 parseprintf(DD_INSTALL, ("init_linemon: driver is \"%s\"\n", dname));
959 #ifdef sun
960 if (dname && !Strcmp(dname, "zs"))
962 return init_zs_linemon(dq, q);
964 else
965 #endif
967 parseprintf(DD_INSTALL, ("init_linemon: driver \"%s\" not suitable for CD monitoring\n", dname));
968 return 0;
971 parseprintf(DD_INSTALL, ("init_linemon: cannot find driver\n"));
972 return 0;
975 static void
976 close_linemon(
977 register queue_t *q,
978 register queue_t *my_q
982 * find appropriate driver dependent routine
984 if (q->q_qinfo && q->q_qinfo->qi_minfo)
986 register char *dname = q->q_qinfo->qi_minfo->mi_idname;
988 #ifdef sun
989 if (dname && !Strcmp(dname, "zs"))
991 close_zs_linemon(q, my_q);
992 return;
994 parseprintf(DD_INSTALL, ("close_linemon: cannot find driver close routine for \"%s\"\n", dname));
995 #endif
997 parseprintf(DD_INSTALL, ("close_linemon: cannot find driver name\n"));
1000 #ifdef sun
1002 #include <sundev/zsreg.h>
1003 #include <sundev/zscom.h>
1004 #include <sundev/zsvar.h>
1006 static unsigned long cdmask = ZSRR0_CD;
1008 struct savedzsops
1010 struct zsops zsops;
1011 struct zsops *oldzsops;
1014 struct zsops *emergencyzs;
1015 extern void zsopinit P((struct zscom *, struct zsops *));
1016 static int zs_xsisr P((struct zscom *)); /* zs external status interupt handler */
1018 static int
1019 init_zs_linemon(
1020 register queue_t *q,
1021 register queue_t *my_q
1024 register struct zscom *zs;
1025 register struct savedzsops *szs;
1026 register parsestream_t *parsestream = (parsestream_t *)(void *)my_q->q_ptr;
1028 * we expect the zsaline pointer in the q_data pointer
1029 * from there on we insert our on EXTERNAL/STATUS ISR routine
1030 * into the interrupt path, before the standard handler
1032 zs = ((struct zsaline *)(void *)q->q_ptr)->za_common;
1033 if (!zs)
1036 * well - not found on startup - just say no (shouldn't happen though)
1038 return 0;
1040 else
1042 unsigned long s;
1045 * we do a direct replacement, in case others fiddle also
1046 * if somebody else grabs our hook and we disconnect
1047 * we are in DEEP trouble - panic is likely to be next, sorry
1049 szs = (struct savedzsops *)(void *)kmem_alloc(sizeof(struct savedzsops));
1051 if (szs == (struct savedzsops *)0)
1053 parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor NOT installed - no memory\n"));
1055 return 0;
1057 else
1059 parsestream->parse_data = (void *)szs;
1061 s = splhigh();
1063 parsestream->parse_dqueue = q; /* remember driver */
1065 szs->zsops = *zs->zs_ops;
1066 szs->zsops.zsop_xsint = zs_xsisr; /* place our bastard */
1067 szs->oldzsops = zs->zs_ops;
1068 emergencyzs = zs->zs_ops;
1070 zsopinit(zs, &szs->zsops); /* hook it up */
1072 (void) splx(s);
1074 parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor installed\n"));
1076 return 1;
1082 * unregister our ISR routine - must call under splhigh()
1084 static void
1085 close_zs_linemon(
1086 register queue_t *q,
1087 register queue_t *my_q
1090 register struct zscom *zs;
1091 register parsestream_t *parsestream = (parsestream_t *)(void *)my_q->q_ptr;
1093 zs = ((struct zsaline *)(void *)q->q_ptr)->za_common;
1094 if (!zs)
1097 * well - not found on startup - just say no (shouldn't happen though)
1099 return;
1101 else
1103 register struct savedzsops *szs = (struct savedzsops *)parsestream->parse_data;
1105 zsopinit(zs, szs->oldzsops); /* reset to previous handler functions */
1107 kmem_free((caddr_t)szs, sizeof (struct savedzsops));
1109 parseprintf(DD_INSTALL, ("close_zs_linemon: CD monitor deleted\n"));
1110 return;
1114 #define MAXDEPTH 50 /* maximum allowed stream crawl */
1116 #ifdef PPS_SYNC
1117 extern void hardpps P((struct timeval *, long));
1118 #ifdef PPS_NEW
1119 extern struct timeval timestamp;
1120 #else
1121 extern struct timeval pps_time;
1122 #endif
1123 #endif
1126 * take external status interrupt (only CD interests us)
1128 static int
1129 zs_xsisr(
1130 struct zscom *zs
1133 register struct zsaline *za = (struct zsaline *)(void *)zs->zs_priv;
1134 register struct zscc_device *zsaddr = zs->zs_addr;
1135 register queue_t *q;
1136 register unsigned char zsstatus;
1137 register int loopcheck;
1138 register char *dname;
1139 #ifdef PPS_SYNC
1140 register unsigned int s;
1141 register long usec;
1142 #endif
1145 * pick up current state
1147 zsstatus = zsaddr->zscc_control;
1149 if ((za->za_rr0 ^ zsstatus) & (cdmask))
1151 timestamp_t cdevent;
1152 register int status;
1154 za->za_rr0 = (za->za_rr0 & ~(cdmask)) | (zsstatus & (cdmask));
1156 #ifdef PPS_SYNC
1157 s = splclock();
1158 #ifdef PPS_NEW
1159 usec = timestamp.tv_usec;
1160 #else
1161 usec = pps_time.tv_usec;
1162 #endif
1163 #endif
1165 * time stamp
1167 uniqtime(&cdevent.tv);
1169 #ifdef PPS_SYNC
1170 (void)splx(s);
1171 #endif
1174 * logical state
1176 status = cd_invert ? (zsstatus & cdmask) == 0 : (zsstatus & cdmask) != 0;
1178 #ifdef PPS_SYNC
1179 if (status)
1181 usec = cdevent.tv.tv_usec - usec;
1182 if (usec < 0)
1183 usec += 1000000;
1185 hardpps(&cdevent.tv, usec);
1187 #endif
1189 q = za->za_ttycommon.t_readq;
1192 * ok - now the hard part - find ourself
1194 loopcheck = MAXDEPTH;
1196 while (q)
1198 if (q->q_qinfo && q->q_qinfo->qi_minfo)
1200 dname = q->q_qinfo->qi_minfo->mi_idname;
1202 if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname))
1205 * back home - phew (hopping along stream queues might
1206 * prove dangerous to your health)
1209 if ((((parsestream_t *)(void *)q->q_ptr)->parse_status & PARSE_ENABLE) &&
1210 parse_iopps(&((parsestream_t *)(void *)q->q_ptr)->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &cdevent))
1213 * XXX - currently we do not pass up the message, as
1214 * we should.
1215 * for a correct behaviour wee need to block out
1216 * processing until parse_iodone has been posted via
1217 * a softcall-ed routine which does the message pass-up
1218 * right now PPS information relies on input being
1219 * received
1221 parse_iodone(&((parsestream_t *)(void *)q->q_ptr)->parse_io);
1224 if (status)
1226 ((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.tv = cdevent.tv;
1227 ++(((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.serial);
1230 parseprintf(DD_ISR, ("zs_xsisr: CD event %s has been posted for \"%s\"\n", status ? "ONE" : "ZERO", dname));
1231 break;
1235 q = q->q_next;
1237 if (!loopcheck--)
1239 panic("zs_xsisr: STREAMS Queue corrupted - CD event");
1244 * only pretend that CD has been handled
1246 ZSDELAY(2);
1248 if (!((za->za_rr0 ^ zsstatus) & ~(cdmask)))
1251 * all done - kill status indication and return
1253 zsaddr->zscc_control = ZSWR0_RESET_STATUS; /* might kill other conditions here */
1254 return 0;
1258 if (zsstatus & cdmask) /* fake CARRIER status */
1259 za->za_flags |= ZAS_CARR_ON;
1260 else
1261 za->za_flags &= ~ZAS_CARR_ON;
1264 * we are now gathered here to process some unusual external status
1265 * interrupts.
1266 * any CD events have also been handled and shouldn't be processed
1267 * by the original routine (unless we have a VERY busy port pin)
1268 * some initializations are done here, which could have been done before for
1269 * both code paths but have been avoided for minimum path length to
1270 * the uniq_time routine
1272 dname = (char *) 0;
1273 q = za->za_ttycommon.t_readq;
1275 loopcheck = MAXDEPTH;
1278 * the real thing for everything else ...
1280 while (q)
1282 if (q->q_qinfo && q->q_qinfo->qi_minfo)
1284 dname = q->q_qinfo->qi_minfo->mi_idname;
1285 if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname))
1287 register int (*zsisr) P((struct zscom *));
1290 * back home - phew (hopping along stream queues might
1291 * prove dangerous to your health)
1293 if ((zsisr = ((struct savedzsops *)((parsestream_t *)(void *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint))
1294 return zsisr(zs);
1295 else
1296 panic("zs_xsisr: unable to locate original ISR");
1298 parseprintf(DD_ISR, ("zs_xsisr: non CD event was processed for \"%s\"\n", dname));
1300 * now back to our program ...
1302 return 0;
1306 q = q->q_next;
1308 if (!loopcheck--)
1310 panic("zs_xsisr: STREAMS Queue corrupted - non CD event");
1315 * last resort - shouldn't even come here as it indicates
1316 * corrupted TTY structures
1318 printf("zs_zsisr: looking for \"%s\" - found \"%s\" - taking EMERGENCY path\n", parseinfo.st_rdinit->qi_minfo->mi_idname, dname ? dname : "-NIL-");
1320 if (emergencyzs && emergencyzs->zsop_xsint)
1321 emergencyzs->zsop_xsint(zs);
1322 else
1323 panic("zs_xsisr: no emergency ISR handler");
1324 return 0;
1326 #endif /* sun */
1329 * History:
1331 * parsestreams.c,v
1332 * Revision 4.11 2005/04/16 17:32:10 kardel
1333 * update copyright
1335 * Revision 4.10 2004/11/14 16:06:08 kardel
1336 * update Id tags
1338 * Revision 4.9 2004/11/14 15:29:41 kardel
1339 * support PPSAPI, upgrade Copyright to Berkeley style
1341 * Revision 4.7 1999/11/28 09:13:53 kardel
1342 * RECON_4_0_98F
1344 * Revision 4.6 1998/12/20 23:45:31 kardel
1345 * fix types and warnings
1347 * Revision 4.5 1998/11/15 21:23:38 kardel
1348 * ntp_memset() replicated in Sun kernel files
1350 * Revision 4.4 1998/06/13 12:15:59 kardel
1351 * superfluous variable removed
1353 * Revision 4.3 1998/06/12 15:23:08 kardel
1354 * fix prototypes
1355 * adjust for ansi2knr
1357 * Revision 4.2 1998/05/24 18:16:22 kardel
1358 * moved copy of shadow status to the beginning
1360 * Revision 4.1 1998/05/24 09:38:47 kardel
1361 * streams initiated iopps calls (M_xHANGUP) are now consistent with the
1362 * respective calls from zs_xsisr()
1363 * simulation of CARRIER status to avoid unecessary M_xHANGUP messages
1365 * Revision 4.0 1998/04/10 19:45:38 kardel
1366 * Start 4.0 release version numbering
1368 * from V3 3.37 log info deleted 1998/04/11 kardel