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