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 Universitaet Erlangen-Nuernberg, 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
Strlen(register const char * s)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
Strncpy(register char * t,register char * s,register int c)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
Strcmp(register const char * s,register const char * t)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
Strncmp(register char * s,register char * t,register int n)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
ntp_memset(char * a,int x,int c)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
xxxinit(unsigned int fc,struct vddrv * vdp,addr_t vdin,struct vdstat * vds)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
setup_stream(queue_t * q,int mode)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
parseopen(queue_t * q,dev_t dev,int flag,int sflag)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
parseclose(queue_t * q,int flags)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
parsersvc(queue_t * q)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
parsewput(queue_t * q,register mblk_t * mp)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
rdchar(register mblk_t ** mp)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
parserput(queue_t * q,mblk_t * mp)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
init_linemon(register queue_t * q)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
close_linemon(register queue_t * q,register queue_t * my_q)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
init_zs_linemon(register queue_t * q,register queue_t * my_q)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
close_zs_linemon(register queue_t * q,register queue_t * my_q)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
zs_xsisr(struct zscom * zs)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 */
1368