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