Annotation of embedaddon/ntp/libparse/parsesolaris.c, revision 1.1.1.1
1.1 misho 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
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
153: _info(
154: struct modinfo *modinfop
155: )
156: {
157: return (mod_info(&modlinkage, modinfop));
158: }
159:
160: /*ARGSUSED*/
161: int
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 (queue_t *, dev_t *, int, int, cred_t *);
177: static int parseclose (queue_t *, int);
178: static int parsewput (queue_t *, mblk_t *);
179: static int parserput (queue_t *, mblk_t *);
180: static int parsersvc (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 (queue_t *);
248: static void close_linemon (queue_t *, queue_t *);
249:
250: #define M_PARSE 0x0001
251: #define M_NOPARSE 0x0002
252:
253: void
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
265: pprintf(
266: int lev,
267: 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, form, ap);
277:
278: va_end(ap);
279: }
280:
281: static int
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
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
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
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
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
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
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 c_time;
645: timespec_t hres_time;
646:
647: /*
648: * get time on packet delivery
649: */
650: gethrestime(&hres_time);
651: c_time.tv.tv_sec = hres_time.tv_sec;
652: c_time.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, &c_time))
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, &c_time))
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 c_time;
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: c_time.tv.tv_sec = hres_time.tv_sec;
733: c_time.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, &c_time))
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 = c_time.tv;
763: ++(parse->parse_ppsclockev.serial);
764: }
765: }
766: }
767: return 0;
768: }
769:
770: static int init_zs_linemon (queue_t *, queue_t *); /* handle line monitor for "zs" driver */
771: static void close_zs_linemon (queue_t *, queue_t *);
772:
773: /*-------------------- CD isr status monitor ---------------*/
774:
775: static int
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
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 (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
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 (*) (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 (*) (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
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
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) (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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>