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