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