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