/*
* /src/NTP/ntp4-dev/libparse/parsesolaris.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A
*
* parsesolaris.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A
*
* STREAMS module for reference clocks
*
* Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> 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.
*
*/
/*
* 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 = modlstrmod.strmod_linkinfo;
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))
{
strlcpy(t, s, (unsigned)(S - s));
}
}
return (mod_install(&modlinkage));
}
static int parseopen (queue_t *, dev_t *, int, int, cred_t *);
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 struct module_info driverinfo =
{
0, /* module ID number */
fmod_templ.f_name, /* module name - why repeated here ? compat ?*/
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 */
};
/*--------------- 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 */
#ifdef PARSEDEBUG
int parsedebug = ~0;
#else
int parsedebug = 0;
#endif
pprintf(DD_OPEN, "parse: OPEN - parse area q=%x, q->q_ptr=%x\n", q, q->q_ptr);
WR(q)->q_ptr = q->q_ptr;
pprintf(DD_OPEN, "parse: OPEN - WQ parse area q=%x, q->q_ptr=%x\n", WR(q), WR(q)->q_ptr);
pprintf(DD_OPEN, "parse: OPEN - initializing io subsystem q=%x\n", q);
if (!parse_ioinit(&parse->parse_io))
{
/*
* ok guys - beat it
*/
qprocsoff(q);
kmem_free((caddr_t)parse, sizeof(parsestream_t));
return EIO;
}
pprintf(DD_OPEN, "parse: OPEN - initializing stream q=%x\n", q);
if (setup_stream(q, M_PARSE))
{
(void) init_linemon(q); /* hook up PPS ISR routines if possible */
pprintf(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)
{
cmn_err(CE_CONT, "?%s: Copyright (c) 1993-2005, Frank Kardel\n", modlstrmod.strmod_linkinfo);
notice = 1;
}
return 0;
}
else
{
qprocsoff(q);
kmem_free((caddr_t)parse, sizeof(parsestream_t));
return EIO;
}
}
/*ARGSUSED*/
static int
parseclose(
queue_t *q,
int flags
)
{
register parsestream_t *parse = (parsestream_t *)q->q_ptr;
register unsigned long s;
pprintf(DD_CLOSE, "parse: CLOSE\n");
qprocsoff(q);
s = splhigh();
if (parse->parse_dqueue)
close_linemon(parse->parse_dqueue, q);
parse->parse_dqueue = (queue_t *)0;
/*
* do ioctls and
* send stuff down - dont care about
* flow control
*/
static int
parsewput(
queue_t *q,
mblk_t *mp
)
{
register int ok = 1;
register mblk_t *datap;
register struct iocblk *iocp;
parsestream_t *parse = (parsestream_t *)q->q_ptr;
case PARSEIOC_TIMECODE:
case PARSEIOC_SETFMT:
case PARSEIOC_GETFMT:
case PARSEIOC_SETCS:
if (iocp->ioc_count == sizeof(parsectl_t))
{
parsectl_t *dct = (void *)mp->b_cont->b_rptr;
switch (iocp->ioc_cmd)
{
case PARSEIOC_TIMECODE:
pprintf(DD_WPUT, "parse: parsewput - PARSEIOC_TIMECODE\n");
ok = parse_timecode(dct, &parse->parse_io);
break;
case PARSEIOC_SETFMT:
pprintf(DD_WPUT, "parse: parsewput - PARSEIOC_SETFMT\n");
ok = parse_setfmt(dct, &parse->parse_io);
break;
case PARSEIOC_GETFMT:
pprintf(DD_WPUT, "parse: parsewput - PARSEIOC_GETFMT\n");
ok = parse_getfmt(dct, &parse->parse_io);
break;
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
*/
pprintf(DD_RPUT, "parse: parserput - forward type 0x%x\n", type);
case M_BREAK:
case M_DATA:
{
register parsestream_t * parse = (parsestream_t *)q->q_ptr;
register mblk_t *nmp;
register unsigned long ch;
timestamp_t c_time;
timespec_t hres_time;
/*
* get time on packet delivery
*/
gethrestime(&hres_time);
c_time.tv.tv_sec = hres_time.tv_sec;
c_time.tv.tv_usec = hres_time.tv_nsec / 1000;
if (!(parse->parse_status & PARSE_ENABLE))
{
pprintf(DD_RPUT, "parse: parserput - parser disabled - forward type 0x%x\n", type);
if (canputnext(q) || (mp->b_datap->db_type > QPCTL))
{
putnext(q, mp);
}
else
putq(q, mp);
}
else
{
pprintf(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, &c_time))
{
/*
* up up and away (hopefully ...)
* don't press it if resources are tight or nobody wants it
*/
nmp = (mblk_t *)NULL;
if (canputnext(parse->parse_queue) && (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, &c_time))
{
/*
* up up and away (hopefully ...)
* don't press it if resources are tight or nobody wants it
*/
nmp = (mblk_t *)NULL;
if (canputnext(parse->parse_queue) && (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 *)q->q_ptr;
timestamp_t c_time;
timespec_t hres_time;
register mblk_t *nmp;
register int status = cd_invert ^ (type == M_UNHANGUP);
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(
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 */
}
static int
init_zs_linemon(
queue_t *q,
queue_t *my_q
)
{
register struct zscom *zs;
register struct savedzsops *szs;
register parsestream_t *parsestream = (parsestream_t *)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 asyncline *)q->q_ptr)->za_common;
if (!zs)
{
/*
* well - not found on startup - just say no (shouldn't happen though)
*/
return 0;
}
else
{
/*
* 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 *) kmem_alloc(sizeof(struct savedzsops), KM_SLEEP);
if (szs == (struct savedzsops *)0)
{
pprintf(DD_INSTALL, "init_zs_linemon: CD monitor NOT installed - no memory\n");
zs->zs_ops = &szs->zsops; /* hook it up */
/*
* XXX: this is usually done via zsopinit()
* - have yet to find a way to call that routine
*/
zs->zs_xsint = (void (*) (struct zscom *))zs_xsisr;
mutex_exit(zs->zs_excl);
pprintf(DD_INSTALL, "init_zs_linemon: CD monitor installed\n");
zs = ((struct asyncline *)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;
mutex_enter(zs->zs_excl);
zs->zs_ops = szs->oldzsops; /* reset to previous handler functions */
/*
* XXX: revert xsint (usually done via zsopinit() - have still to find
* a way to call that bugger
*/
zs->zs_xsint = zs->zs_ops->zsop_xsint;
/*
* logical state
*/
status = cd_invert ? cdstate == 0 : cdstate != 0;
/*
* 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 *)q->q_ptr)->parse_status & PARSE_ENABLE) &&
parse_iopps(&((parsestream_t *)q->q_ptr)->parse_io, 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 *)q->q_ptr)->parse_io);
}
if (status)
{
((parsestream_t *)q->q_ptr)->parse_ppsclockev.tv = cdevent.tv;
++(((parsestream_t *)q->q_ptr)->parse_ppsclockev.serial);
}
pprintf(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");
}
}
if (cdstate) /* fake CARRIER status - XXX currently not coordinated */
za->za_flags |= ZAS_CARR_ON;
else
za->za_flags &= ~ZAS_CARR_ON;
/*
* only pretend that CD and ignored transistion (SYNC,CTS)
* have been handled
*/
za->za_rr0 = (za->za_rr0 & ~ZSRR0_IGNORE) | (zsstatus & ZSRR0_IGNORE);
if (((za->za_rr0 ^ zsstatus) & ~ZSRR0_IGNORE) == 0)
{
/*
* all done - kill status indication and return
*/
SCC_WRITE0(ZSWR0_RESET_STATUS); /* might kill other conditions here */
return;
}
}
pprintf(DD_ISR, "zs_xsisr: non CD event 0x%x for \"%s\"\n",
(za->za_rr0 ^ zsstatus) & ~ZSRR0_CD,dname);
/*
* 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 avioded 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 void (*zsisr) (struct zscom *);
/*
* back home - phew (hopping along stream queues might
* prove dangerous to your health)
*/
if ((zsisr = ((struct savedzsops *)((parsestream_t *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint))
zsisr(zs);
else
panic("zs_xsisr: unable to locate original ISR");
pprintf(DD_ISR, "zs_xsisr: non CD event was processed for \"%s\"\n", dname);
/*
* now back to our program ...
*/
return;
}
}
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");
}
#endif /* sun */
/*
* History:
*
* parsesolaris.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.6 1998/11/15 21:56:08 kardel
* ntp_memset not necessary
*
* Revision 4.5 1998/11/15 21:23:37 kardel
* ntp_memset() replicated in Sun kernel files
*
* Revision 4.4 1998/06/14 21:09:40 kardel
* Sun acc cleanup
*
* Revision 4.3 1998/06/13 12:14:59 kardel
* more prototypes
* fix name clashes
* allow for ansi2knr
*
* Revision 4.2 1998/06/12 15:23:08 kardel
* fix prototypes
* adjust for ansi2knr
*
* Revision 4.1 1998/05/24 09:38:46 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.28 log info deleted 1998/04/11 kardel
*/