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