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