/* * /src/NTP/ntp4-dev/libparse/parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A * * parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A * * STREAMS module for reference clocks * (SunOS4.x) * * Copyright (c) 1995-2005 by Frank Kardel ntp.org> * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #define KERNEL /* MUST */ #define VDDRV /* SHOULD */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef lint static char rcsid[] = "parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A"; #endif #ifndef KERNEL #include "Bletch: MUST COMPILE WITH KERNEL DEFINE" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef VDDRV #include #endif #include "ntp_stdlib.h" #include "ntp_fp.h" /* * just make checking compilers more silent */ extern int printf (const char *, ...); extern int putctl1 (queue_t *, int, int); extern int canput (queue_t *); extern void putbq (queue_t *, mblk_t *); extern void freeb (mblk_t *); extern void qreply (queue_t *, mblk_t *); extern void freemsg (mblk_t *); extern void panic (const char *, ...); extern void usec_delay (int); #include "parse.h" #include "sys/parsestreams.h" /* * use microtime instead of uniqtime if advised to */ #ifdef MICROTIME #define uniqtime microtime #endif #ifdef VDDRV static unsigned int parsebusy = 0; /*--------------- loadable driver section -----------------------------*/ extern struct streamtab parseinfo; #ifdef PPS_SYNC static char mnam[] = "PARSEPPS "; /* name this baby - keep room for revision number */ #else static char mnam[] = "PARSE "; /* name this baby - keep room for revision number */ #endif struct vdldrv parsesync_vd = { VDMAGIC_PSEUDO, /* nothing like a real driver - a STREAMS module */ mnam, }; /* * strings support usually not in kernel */ static int Strlen( register const char *s ) { register int c; c = 0; if (s) { while (*s++) { c++; } } return c; } static void Strncpy( register char *t, register char *s, register int c ) { if (s && t) { while ((c-- > 0) && (*t++ = *s++)) ; } } static int Strcmp( register const char *s, register const char *t ) { register int c = 0; if (!s || !t || (s == t)) { return 0; } while (!(c = *s++ - *t++) && *s && *t) /* empty loop */; return c; } static int Strncmp( register char *s, register char *t, register int n ) { register int c = 0; if (!s || !t || (s == t)) { return 0; } while (n-- && !(c = *s++ - *t++) && *s && *t) /* empty loop */; return c; } void ntp_memset( char *a, int x, int c ) { while (c-- > 0) *a++ = x; } /* * driver init routine * since no mechanism gets us into and out of the fmodsw, we have to * do it ourselves */ /*ARGSUSED*/ int xxxinit( unsigned int fc, struct vddrv *vdp, addr_t vdin, struct vdstat *vds ) { extern struct fmodsw fmodsw[]; extern int fmodcnt; struct fmodsw *fm = fmodsw; struct fmodsw *fmend = &fmodsw[fmodcnt]; struct fmodsw *ifm = (struct fmodsw *)0; char *mname = parseinfo.st_rdinit->qi_minfo->mi_idname; switch (fc) { case VDLOAD: vdp->vdd_vdtab = (struct vdlinkage *)&parsesync_vd; /* * now, jog along fmodsw scanning for an empty slot * and deposit our name there */ while (fm <= fmend) { if (!Strncmp(fm->f_name, mname, FMNAMESZ)) { printf("vddrinit[%s]: STREAMS module already loaded.\n", mname); return(EBUSY); } else if ((ifm == (struct fmodsw *)0) && (fm->f_name[0] == '\0') && (fm->f_str == (struct streamtab *)0)) { /* * got one - so move in */ ifm = fm; break; } fm++; } if (ifm == (struct fmodsw *)0) { printf("vddrinit[%s]: no slot free for STREAMS module\n", mname); return (ENOSPC); } else { static char revision[] = "4.7"; char *s, *S, *t; s = rcsid; /* NOOP - keep compilers happy */ Strncpy(ifm->f_name, mname, FMNAMESZ); ifm->f_name[FMNAMESZ] = '\0'; ifm->f_str = &parseinfo; /* * copy RCS revision into Drv_name * * are we forcing RCS here to do things it was not built for ? */ s = revision; if (*s == '$') { /* * skip "$Revision: " * if present. - not necessary on a -kv co (cvs export) */ while (*s && (*s != ' ')) { s++; } if (*s == ' ') s++; } t = parsesync_vd.Drv_name; while (*t && (*t != ' ')) { t++; } if (*t == ' ') t++; S = s; while (*S && (((*S >= '0') && (*S <= '9')) || (*S == '.'))) { S++; } if (*s && *t && (S > s)) { if (Strlen(t) >= (S - s)) { (void) Strncpy(t, s, S - s); } } return (0); } break; case VDUNLOAD: if (parsebusy > 0) { printf("vddrinit[%s]: STREAMS module has still %d instances active.\n", mname, parsebusy); return (EBUSY); } else { while (fm <= fmend) { if (!Strncmp(fm->f_name, mname, FMNAMESZ)) { /* * got it - kill entry */ fm->f_name[0] = '\0'; fm->f_str = (struct streamtab *)0; fm++; break; } fm++; } if (fm > fmend) { printf("vddrinit[%s]: cannot find entry for STREAMS module\n", mname); return (ENXIO); } else return (0); } case VDSTAT: return (0); default: return (EIO); } return EIO; } #endif /*--------------- stream module definition ----------------------------*/ static int parseopen (queue_t *, dev_t, int, int); static int parseclose (queue_t *, int); static int parsewput (queue_t *, mblk_t *); static int parserput (queue_t *, mblk_t *); static int parsersvc (queue_t *); static char mn[] = "parse"; static struct module_info driverinfo = { 0, /* module ID number */ mn, /* module name */ 0, /* minimum accepted packet size */ INFPSZ, /* maximum accepted packet size */ 1, /* high water mark - flow control */ 0 /* low water mark - flow control */ }; static struct qinit rinit = /* read queue definition */ { parserput, /* put procedure */ parsersvc, /* service procedure */ parseopen, /* open procedure */ parseclose, /* close procedure */ NULL, /* admin procedure - NOT USED FOR NOW */ &driverinfo, /* information structure */ NULL /* statistics */ }; static struct qinit winit = /* write queue definition */ { parsewput, /* put procedure */ NULL, /* service procedure */ NULL, /* open procedure */ NULL, /* close procedure */ NULL, /* admin procedure - NOT USED FOR NOW */ &driverinfo, /* information structure */ NULL /* statistics */ }; struct streamtab parseinfo = /* stream info element for dpr driver */ { &rinit, /* read queue */ &winit, /* write queue */ NULL, /* read mux */ NULL, /* write mux */ NULL /* module auto push */ }; /*--------------- driver data structures ----------------------------*/ /* * we usually have an inverted signal - but you * can change this to suit your needs */ int cd_invert = 1; /* invert status of CD line - PPS support via CD input */ int parsedebug = ~0; extern void uniqtime (struct timeval *); /*--------------- module implementation -----------------------------*/ #define TIMEVAL_USADD(_X_, _US_) {\ (_X_)->tv_usec += (_US_);\ if ((_X_)->tv_usec >= 1000000)\ {\ (_X_)->tv_sec++;\ (_X_)->tv_usec -= 1000000;\ }\ } while (0) static int init_linemon (queue_t *); static void close_linemon (queue_t *, queue_t *); #define M_PARSE 0x0001 #define M_NOPARSE 0x0002 static int setup_stream( queue_t *q, int mode ) { mblk_t *mp; mp = allocb(sizeof(struct stroptions), BPRI_MED); if (mp) { struct stroptions *str = (struct stroptions *)(void *)mp->b_rptr; str->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT; str->so_readopt = (mode == M_PARSE) ? RMSGD : RNORM; str->so_hiwat = (mode == M_PARSE) ? sizeof(parsetime_t) : 256; str->so_lowat = 0; mp->b_datap->db_type = M_SETOPTS; mp->b_wptr += sizeof(struct stroptions); putnext(q, mp); return putctl1(WR(q)->q_next, M_CTL, (mode == M_PARSE) ? MC_SERVICEIMM : MC_SERVICEDEF); } else { parseprintf(DD_OPEN,("parse: setup_stream - FAILED - no MEMORY for allocb\n")); return 0; } } /*ARGSUSED*/ static int parseopen( queue_t *q, dev_t dev, int flag, int sflag ) { register parsestream_t *parse; static int notice = 0; parseprintf(DD_OPEN,("parse: OPEN\n")); if (sflag != MODOPEN) { /* open only for modules */ parseprintf(DD_OPEN,("parse: OPEN - FAILED - not MODOPEN\n")); return OPENFAIL; } if (q->q_ptr != (caddr_t)NULL) { u.u_error = EBUSY; parseprintf(DD_OPEN,("parse: OPEN - FAILED - EXCLUSIVE ONLY\n")); return OPENFAIL; } #ifdef VDDRV parsebusy++; #endif q->q_ptr = (caddr_t)kmem_alloc(sizeof(parsestream_t)); if (q->q_ptr == (caddr_t)0) { parseprintf(DD_OPEN,("parse: OPEN - FAILED - no memory\n")); #ifdef VDDRV parsebusy--; #endif return OPENFAIL; } WR(q)->q_ptr = q->q_ptr; parse = (parsestream_t *)(void *)q->q_ptr; bzero((caddr_t)parse, sizeof(*parse)); parse->parse_queue = q; parse->parse_status = PARSE_ENABLE; parse->parse_ppsclockev.tv.tv_sec = 0; parse->parse_ppsclockev.tv.tv_usec = 0; parse->parse_ppsclockev.serial = 0; if (!parse_ioinit(&parse->parse_io)) { /* * ok guys - beat it */ kmem_free((caddr_t)parse, sizeof(parsestream_t)); #ifdef VDDRV parsebusy--; #endif return OPENFAIL; } if (setup_stream(q, M_PARSE)) { (void) init_linemon(q); /* hook up PPS ISR routines if possible */ parseprintf(DD_OPEN,("parse: OPEN - SUCCEEDED\n")); /* * I know that you know the delete key, but you didn't write this * code, did you ? - So, keep the message in here. */ if (!notice) { #ifdef VDDRV printf("%s: Copyright (C) 1991-2005, Frank Kardel\n", parsesync_vd.Drv_name); #else printf("%s: Copyright (C) 1991-2005, Frank Kardel\n", "parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A"); #endif notice = 1; } return MODOPEN; } else { kmem_free((caddr_t)parse, sizeof(parsestream_t)); #ifdef VDDRV parsebusy--; #endif return OPENFAIL; } } /*ARGSUSED*/ static int parseclose( queue_t *q, int flags ) { register parsestream_t *parse = (parsestream_t *)(void *)q->q_ptr; register unsigned long s; parseprintf(DD_CLOSE,("parse: CLOSE\n")); s = splhigh(); if (parse->parse_dqueue) close_linemon(parse->parse_dqueue, q); parse->parse_dqueue = (queue_t *)0; (void) splx(s); parse_ioend(&parse->parse_io); kmem_free((caddr_t)parse, sizeof(parsestream_t)); q->q_ptr = (caddr_t)NULL; WR(q)->q_ptr = (caddr_t)NULL; #ifdef VDDRV parsebusy--; #endif return 0; } /* * move unrecognized stuff upward */ static int parsersvc( queue_t *q ) { mblk_t *mp; while ((mp = getq(q))) { if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) { putnext(q, mp); parseprintf(DD_RSVC,("parse: RSVC - putnext\n")); } else { putbq(q, mp); parseprintf(DD_RSVC,("parse: RSVC - flow control wait\n")); break; } } return 0; } /* * do ioctls and * send stuff down - dont care about * flow control */ static int parsewput( queue_t *q, register mblk_t *mp ) { register int ok = 1; register mblk_t *datap; register struct iocblk *iocp; parsestream_t *parse = (parsestream_t *)(void *)q->q_ptr; parseprintf(DD_WPUT,("parse: parsewput\n")); switch (mp->b_datap->db_type) { default: putnext(q, mp); break; case M_IOCTL: iocp = (struct iocblk *)(void *)mp->b_rptr; switch (iocp->ioc_cmd) { default: parseprintf(DD_WPUT,("parse: parsewput - forward M_IOCTL\n")); putnext(q, mp); break; case CIOGETEV: /* * taken from Craig Leres ppsclock module (and modified) */ datap = allocb(sizeof(struct ppsclockev), BPRI_MED); if (datap == NULL || mp->b_cont) { mp->b_datap->db_type = M_IOCNAK; iocp->ioc_error = (datap == NULL) ? ENOMEM : EINVAL; if (datap != NULL) freeb(datap); qreply(q, mp); break; } mp->b_cont = datap; *(struct ppsclockev *)(void *)datap->b_wptr = parse->parse_ppsclockev; datap->b_wptr += sizeof(struct ppsclockev) / sizeof(*datap->b_wptr); mp->b_datap->db_type = M_IOCACK; iocp->ioc_count = sizeof(struct ppsclockev); qreply(q, mp); break; case PARSEIOC_ENABLE: case PARSEIOC_DISABLE: { parse->parse_status = (parse->parse_status & (unsigned)~PARSE_ENABLE) | (iocp->ioc_cmd == PARSEIOC_ENABLE) ? PARSE_ENABLE : 0; if (!setup_stream(RD(q), (parse->parse_status & PARSE_ENABLE) ? M_PARSE : M_NOPARSE)) { mp->b_datap->db_type = M_IOCNAK; } else { mp->b_datap->db_type = M_IOCACK; } qreply(q, mp); break; } case PARSEIOC_TIMECODE: case PARSEIOC_SETFMT: case PARSEIOC_GETFMT: case PARSEIOC_SETCS: if (iocp->ioc_count == sizeof(parsectl_t)) { parsectl_t *dct = (parsectl_t *)(void *)mp->b_cont->b_rptr; switch (iocp->ioc_cmd) { case PARSEIOC_TIMECODE: parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_TIMECODE\n")); ok = parse_timecode(dct, &parse->parse_io); break; case PARSEIOC_SETFMT: parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETFMT\n")); ok = parse_setfmt(dct, &parse->parse_io); break; case PARSEIOC_GETFMT: parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_GETFMT\n")); ok = parse_getfmt(dct, &parse->parse_io); break; case PARSEIOC_SETCS: parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETCS\n")); ok = parse_setcs(dct, &parse->parse_io); break; } mp->b_datap->db_type = ok ? M_IOCACK : M_IOCNAK; } else { mp->b_datap->db_type = M_IOCNAK; } parseprintf(DD_WPUT,("parse: parsewput qreply - %s\n", (mp->b_datap->db_type == M_IOCNAK) ? "M_IOCNAK" : "M_IOCACK")); qreply(q, mp); break; } } return 0; } /* * read characters from streams buffers */ static unsigned long rdchar( register mblk_t **mp ) { while (*mp != (mblk_t *)NULL) { if ((*mp)->b_wptr - (*mp)->b_rptr) { return (unsigned long)(*(unsigned char *)((*mp)->b_rptr++)); } else { register mblk_t *mmp = *mp; *mp = (*mp)->b_cont; freeb(mmp); } } return (unsigned)~0; } /* * convert incoming data */ static int parserput( queue_t *q, mblk_t *mp ) { unsigned char type; switch (type = mp->b_datap->db_type) { default: /* * anything we don't know will be put on queue * the service routine will move it to the next one */ parseprintf(DD_RPUT,("parse: parserput - forward type 0x%x\n", type)); if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) { putnext(q, mp); } else putq(q, mp); break; case M_BREAK: case M_DATA: { register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr; register mblk_t *nmp; register unsigned long ch; timestamp_t ctime; /* * get time on packet delivery */ uniqtime(&ctime.tv); if (!(parse->parse_status & PARSE_ENABLE)) { parseprintf(DD_RPUT,("parse: parserput - parser disabled - forward type 0x%x\n", type)); if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) { putnext(q, mp); } else putq(q, mp); } else { parseprintf(DD_RPUT,("parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK")); if (type == M_DATA) { /* * parse packet looking for start an end characters */ while (mp != (mblk_t *)NULL) { ch = rdchar(&mp); if (ch != ~0 && parse_ioread(&parse->parse_io, (unsigned int)ch, &ctime)) { /* * up up and away (hopefully ...) * don't press it if resources are tight or nobody wants it */ nmp = (mblk_t *)NULL; if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) { bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); nmp->b_wptr += sizeof(parsetime_t); putnext(parse->parse_queue, nmp); } else if (nmp) freemsg(nmp); parse_iodone(&parse->parse_io); } } } else { if (parse_ioread(&parse->parse_io, (unsigned int)0, &ctime)) { /* * up up and away (hopefully ...) * don't press it if resources are tight or nobody wants it */ nmp = (mblk_t *)NULL; if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) { bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); nmp->b_wptr += sizeof(parsetime_t); putnext(parse->parse_queue, nmp); } else if (nmp) freemsg(nmp); parse_iodone(&parse->parse_io); } freemsg(mp); } break; } } /* * CD PPS support for non direct ISR hack */ case M_HANGUP: case M_UNHANGUP: { register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr; timestamp_t ctime; register mblk_t *nmp; register int status = cd_invert ^ (type == M_UNHANGUP); uniqtime(&ctime.tv); parseprintf(DD_RPUT,("parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN")); if ((parse->parse_status & PARSE_ENABLE) && parse_iopps(&parse->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &ctime)) { nmp = (mblk_t *)NULL; if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) { bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); nmp->b_wptr += sizeof(parsetime_t); putnext(parse->parse_queue, nmp); } else if (nmp) freemsg(nmp); parse_iodone(&parse->parse_io); freemsg(mp); } else if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) { putnext(q, mp); } else putq(q, mp); if (status) { parse->parse_ppsclockev.tv = ctime.tv; ++(parse->parse_ppsclockev.serial); } } } return 0; } static int init_zs_linemon (queue_t *, queue_t *); /* handle line monitor for "zs" driver */ static void close_zs_linemon (queue_t *, queue_t *); /*-------------------- CD isr status monitor ---------------*/ static int init_linemon( register queue_t *q ) { register queue_t *dq; dq = WR(q); /* * we ARE doing very bad things down here (basically stealing ISR * hooks) * * so we chase down the STREAMS stack searching for the driver * and if this is a known driver we insert our ISR routine for * status changes in to the ExternalStatus handling hook */ while (dq->q_next) { dq = dq->q_next; /* skip down to driver */ } /* * find appropriate driver dependent routine */ if (dq->q_qinfo && dq->q_qinfo->qi_minfo) { register char *dname = dq->q_qinfo->qi_minfo->mi_idname; parseprintf(DD_INSTALL, ("init_linemon: driver is \"%s\"\n", dname)); #ifdef sun if (dname && !Strcmp(dname, "zs")) { return init_zs_linemon(dq, q); } else #endif { parseprintf(DD_INSTALL, ("init_linemon: driver \"%s\" not suitable for CD monitoring\n", dname)); return 0; } } parseprintf(DD_INSTALL, ("init_linemon: cannot find driver\n")); return 0; } static void close_linemon( register queue_t *q, register queue_t *my_q ) { /* * find appropriate driver dependent routine */ if (q->q_qinfo && q->q_qinfo->qi_minfo) { register char *dname = q->q_qinfo->qi_minfo->mi_idname; #ifdef sun if (dname && !Strcmp(dname, "zs")) { close_zs_linemon(q, my_q); return; } parseprintf(DD_INSTALL, ("close_linemon: cannot find driver close routine for \"%s\"\n", dname)); #endif } parseprintf(DD_INSTALL, ("close_linemon: cannot find driver name\n")); } #ifdef sun #include #include #include static unsigned long cdmask = ZSRR0_CD; struct savedzsops { struct zsops zsops; struct zsops *oldzsops; }; struct zsops *emergencyzs; extern void zsopinit (struct zscom *, struct zsops *); static int zs_xsisr (struct zscom *); /* zs external status interupt handler */ static int init_zs_linemon( register queue_t *q, register queue_t *my_q ) { register struct zscom *zs; register struct savedzsops *szs; register parsestream_t *parsestream = (parsestream_t *)(void *)my_q->q_ptr; /* * we expect the zsaline pointer in the q_data pointer * from there on we insert our on EXTERNAL/STATUS ISR routine * into the interrupt path, before the standard handler */ zs = ((struct zsaline *)(void *)q->q_ptr)->za_common; if (!zs) { /* * well - not found on startup - just say no (shouldn't happen though) */ return 0; } else { unsigned long s; /* * we do a direct replacement, in case others fiddle also * if somebody else grabs our hook and we disconnect * we are in DEEP trouble - panic is likely to be next, sorry */ szs = (struct savedzsops *)(void *)kmem_alloc(sizeof(struct savedzsops)); if (szs == (struct savedzsops *)0) { parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor NOT installed - no memory\n")); return 0; } else { parsestream->parse_data = (void *)szs; s = splhigh(); parsestream->parse_dqueue = q; /* remember driver */ szs->zsops = *zs->zs_ops; szs->zsops.zsop_xsint = zs_xsisr; /* place our bastard */ szs->oldzsops = zs->zs_ops; emergencyzs = zs->zs_ops; zsopinit(zs, &szs->zsops); /* hook it up */ (void) splx(s); parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor installed\n")); return 1; } } } /* * unregister our ISR routine - must call under splhigh() */ static void close_zs_linemon( register queue_t *q, register queue_t *my_q ) { register struct zscom *zs; register parsestream_t *parsestream = (parsestream_t *)(void *)my_q->q_ptr; zs = ((struct zsaline *)(void *)q->q_ptr)->za_common; if (!zs) { /* * well - not found on startup - just say no (shouldn't happen though) */ return; } else { register struct savedzsops *szs = (struct savedzsops *)parsestream->parse_data; zsopinit(zs, szs->oldzsops); /* reset to previous handler functions */ kmem_free((caddr_t)szs, sizeof (struct savedzsops)); parseprintf(DD_INSTALL, ("close_zs_linemon: CD monitor deleted\n")); return; } } #define MAXDEPTH 50 /* maximum allowed stream crawl */ #ifdef PPS_SYNC extern void hardpps (struct timeval *, long); #ifdef PPS_NEW extern struct timeval timestamp; #else extern struct timeval pps_time; #endif #endif /* * take external status interrupt (only CD interests us) */ static int zs_xsisr( struct zscom *zs ) { register struct zsaline *za = (struct zsaline *)(void *)zs->zs_priv; register struct zscc_device *zsaddr = zs->zs_addr; register queue_t *q; register unsigned char zsstatus; register int loopcheck; register char *dname; #ifdef PPS_SYNC register unsigned int s; register long usec; #endif /* * pick up current state */ zsstatus = zsaddr->zscc_control; if ((za->za_rr0 ^ zsstatus) & (cdmask)) { timestamp_t cdevent; register int status; za->za_rr0 = (za->za_rr0 & ~(cdmask)) | (zsstatus & (cdmask)); #ifdef PPS_SYNC s = splclock(); #ifdef PPS_NEW usec = timestamp.tv_usec; #else usec = pps_time.tv_usec; #endif #endif /* * time stamp */ uniqtime(&cdevent.tv); #ifdef PPS_SYNC (void)splx(s); #endif /* * logical state */ status = cd_invert ? (zsstatus & cdmask) == 0 : (zsstatus & cdmask) != 0; #ifdef PPS_SYNC if (status) { usec = cdevent.tv.tv_usec - usec; if (usec < 0) usec += 1000000; hardpps(&cdevent.tv, usec); } #endif q = za->za_ttycommon.t_readq; /* * ok - now the hard part - find ourself */ loopcheck = MAXDEPTH; while (q) { if (q->q_qinfo && q->q_qinfo->qi_minfo) { dname = q->q_qinfo->qi_minfo->mi_idname; if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname)) { /* * back home - phew (hopping along stream queues might * prove dangerous to your health) */ if ((((parsestream_t *)(void *)q->q_ptr)->parse_status & PARSE_ENABLE) && parse_iopps(&((parsestream_t *)(void *)q->q_ptr)->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &cdevent)) { /* * XXX - currently we do not pass up the message, as * we should. * for a correct behaviour wee need to block out * processing until parse_iodone has been posted via * a softcall-ed routine which does the message pass-up * right now PPS information relies on input being * received */ parse_iodone(&((parsestream_t *)(void *)q->q_ptr)->parse_io); } if (status) { ((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.tv = cdevent.tv; ++(((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.serial); } parseprintf(DD_ISR, ("zs_xsisr: CD event %s has been posted for \"%s\"\n", status ? "ONE" : "ZERO", dname)); break; } } q = q->q_next; if (!loopcheck--) { panic("zs_xsisr: STREAMS Queue corrupted - CD event"); } } /* * only pretend that CD has been handled */ ZSDELAY(2); if (!((za->za_rr0 ^ zsstatus) & ~(cdmask))) { /* * all done - kill status indication and return */ zsaddr->zscc_control = ZSWR0_RESET_STATUS; /* might kill other conditions here */ return 0; } } if (zsstatus & cdmask) /* fake CARRIER status */ za->za_flags |= ZAS_CARR_ON; else za->za_flags &= ~ZAS_CARR_ON; /* * we are now gathered here to process some unusual external status * interrupts. * any CD events have also been handled and shouldn't be processed * by the original routine (unless we have a VERY busy port pin) * some initializations are done here, which could have been done before for * both code paths but have been avoided for minimum path length to * the uniq_time routine */ dname = (char *) 0; q = za->za_ttycommon.t_readq; loopcheck = MAXDEPTH; /* * the real thing for everything else ... */ while (q) { if (q->q_qinfo && q->q_qinfo->qi_minfo) { dname = q->q_qinfo->qi_minfo->mi_idname; if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname)) { register int (*zsisr) (struct zscom *); /* * back home - phew (hopping along stream queues might * prove dangerous to your health) */ if ((zsisr = ((struct savedzsops *)((parsestream_t *)(void *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint)) return zsisr(zs); else panic("zs_xsisr: unable to locate original ISR"); parseprintf(DD_ISR, ("zs_xsisr: non CD event was processed for \"%s\"\n", dname)); /* * now back to our program ... */ return 0; } } q = q->q_next; if (!loopcheck--) { panic("zs_xsisr: STREAMS Queue corrupted - non CD event"); } } /* * last resort - shouldn't even come here as it indicates * corrupted TTY structures */ printf("zs_zsisr: looking for \"%s\" - found \"%s\" - taking EMERGENCY path\n", parseinfo.st_rdinit->qi_minfo->mi_idname, dname ? dname : "-NIL-"); if (emergencyzs && emergencyzs->zsop_xsint) emergencyzs->zsop_xsint(zs); else panic("zs_xsisr: no emergency ISR handler"); return 0; } #endif /* sun */ /* * History: * * parsestreams.c,v * Revision 4.11 2005/04/16 17:32:10 kardel * update copyright * * Revision 4.10 2004/11/14 16:06:08 kardel * update Id tags * * Revision 4.9 2004/11/14 15:29:41 kardel * support PPSAPI, upgrade Copyright to Berkeley style * * Revision 4.7 1999/11/28 09:13:53 kardel * RECON_4_0_98F * * Revision 4.6 1998/12/20 23:45:31 kardel * fix types and warnings * * Revision 4.5 1998/11/15 21:23:38 kardel * ntp_memset() replicated in Sun kernel files * * Revision 4.4 1998/06/13 12:15:59 kardel * superfluous variable removed * * Revision 4.3 1998/06/12 15:23:08 kardel * fix prototypes * adjust for ansi2knr * * Revision 4.2 1998/05/24 18:16:22 kardel * moved copy of shadow status to the beginning * * Revision 4.1 1998/05/24 09:38:47 kardel * streams initiated iopps calls (M_xHANGUP) are now consistent with the * respective calls from zs_xsisr() * simulation of CARRIER status to avoid unecessary M_xHANGUP messages * * Revision 4.0 1998/04/10 19:45:38 kardel * Start 4.0 release version numbering * * from V3 3.37 log info deleted 1998/04/11 kardel */