diff options
author | roberto <roberto@FreeBSD.org> | 1999-12-09 13:01:21 +0000 |
---|---|---|
committer | roberto <roberto@FreeBSD.org> | 1999-12-09 13:01:21 +0000 |
commit | ef64b99e8412f2273dd2e8b3291c2f78ffc4667f (patch) | |
tree | fc0cfa1aab0ff6b228f511b410733ef4f35d1ead /contrib/ntp/libparse/parsestreams.c | |
download | FreeBSD-src-ef64b99e8412f2273dd2e8b3291c2f78ffc4667f.zip FreeBSD-src-ef64b99e8412f2273dd2e8b3291c2f78ffc4667f.tar.gz |
Virgin import of ntpd 4.0.98f
Diffstat (limited to 'contrib/ntp/libparse/parsestreams.c')
-rw-r--r-- | contrib/ntp/libparse/parsestreams.c | 1335 |
1 files changed, 1335 insertions, 0 deletions
diff --git a/contrib/ntp/libparse/parsestreams.c b/contrib/ntp/libparse/parsestreams.c new file mode 100644 index 0000000..1578229 --- /dev/null +++ b/contrib/ntp/libparse/parsestreams.c @@ -0,0 +1,1335 @@ +/* + * /src/NTP/ntp-4/libparse/parsestreams.c,v 4.6 1998/12/20 23:45:31 kardel RELEASE_19990228_A + * + * parsestreams.c,v 4.6 1998/12/20 23:45:31 kardel RELEASE_19990228_A + * + * STREAMS module for reference clocks + * (SunOS4.x) + * + * Copyright (c) 1989-1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#define KERNEL /* MUST */ +#define VDDRV /* SHOULD */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef lint +static char rcsid[] = "parsestreams.c,v 4.6 1998/12/20 23:45:31 kardel RELEASE_19990228_A"; +#endif + +#ifndef KERNEL +#include "Bletch: MUST COMPILE WITH KERNEL DEFINE" +#endif + +#include <sys/types.h> +#include <sys/conf.h> +#include <sys/buf.h> +#include <sys/param.h> +#include <sys/sysmacros.h> +#include <sys/time.h> +#include <sundev/mbvar.h> +#include <sun/autoconf.h> +#include <sys/stream.h> +#include <sys/stropts.h> +#include <sys/dir.h> +#include <sys/signal.h> +#include <sys/termios.h> +#include <sys/termio.h> +#include <sys/ttold.h> +#include <sys/user.h> +#include <sys/tty.h> + +#ifdef VDDRV +#include <sun/vddrv.h> +#endif + +#include "ntp_stdlib.h" +#include "ntp_fp.h" +/* + * just make checking compilers more silent + */ +extern int printf P((const char *, ...)); +extern int putctl1 P((queue_t *, int, int)); +extern int canput P((queue_t *)); +extern void putbq P((queue_t *, mblk_t *)); +extern void freeb P((mblk_t *)); +extern void qreply P((queue_t *, mblk_t *)); +extern void freemsg P((mblk_t *)); +extern void panic P((const char *, ...)); +extern void usec_delay P((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.6"; + 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 P((queue_t *, dev_t, int, int)); +static int parseclose P((queue_t *, int)); +static int parsewput P((queue_t *, mblk_t *)); +static int parserput P((queue_t *, mblk_t *)); +static int parsersvc P((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 P((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 P((queue_t *)); +static void close_linemon P((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-1998, Frank Kardel\n", parsesync_vd.Drv_name); +#else + printf("%s: Copyright (C) 1991-1998, Frank Kardel\n", "parsestreams.c,v 4.6 1998/12/20 23:45:31 kardel RELEASE_19990228_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 P((queue_t *, queue_t *)); /* handle line monitor for "zs" driver */ +static void close_zs_linemon P((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 <sundev/zsreg.h> +#include <sundev/zscom.h> +#include <sundev/zsvar.h> + +static unsigned long cdmask = ZSRR0_CD; + +struct savedzsops +{ + struct zsops zsops; + struct zsops *oldzsops; +}; + +struct zsops *emergencyzs; +extern void zsopinit P((struct zscom *, struct zsops *)); +static int zs_xsisr P((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 P((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) P((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.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 + */ |