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 P((queue_t *, dev_t *, int, int, cred_t *)); 177 static int parseclose P((queue_t *, int)); 178 static int parsewput P((queue_t *, mblk_t *)); 179 static int parserput P((queue_t *, mblk_t *)); 180 static int parsersvc P((queue_t *)); 181 182 static struct module_info driverinfo = 183 { 184 0, /* module ID number */ 185 fmod_templ.f_name, /* module name - why repeated here ? compat ?*/ 186 0, /* minimum accepted packet size */ 187 INFPSZ, /* maximum accepted packet size */ 188 1, /* high water mark - flow control */ 189 0 /* low water mark - flow control */ 190 }; 191 192 static struct qinit rinit = /* read queue definition */ 193 { 194 parserput, /* put procedure */ 195 parsersvc, /* service procedure */ 196 parseopen, /* open procedure */ 197 parseclose, /* close procedure */ 198 NULL, /* admin procedure - NOT USED FOR NOW */ 199 &driverinfo, /* information structure */ 200 NULL /* statistics */ 201 }; 202 203 static struct qinit winit = /* write queue definition */ 204 { 205 parsewput, /* put procedure */ 206 NULL, /* service procedure */ 207 NULL, /* open procedure */ 208 NULL, /* close procedure */ 209 NULL, /* admin procedure - NOT USED FOR NOW */ 210 &driverinfo, /* information structure */ 211 NULL /* statistics */ 212 }; 213 214 static struct streamtab parseinfo = /* stream info element for parse driver */ 215 { 216 &rinit, /* read queue */ 217 &winit, /* write queue */ 218 NULL, /* read mux */ 219 NULL /* write mux */ 220 }; 221 222 /*--------------- driver data structures ----------------------------*/ 223 224 /* 225 * we usually have an inverted signal - but you 226 * can change this to suit your needs 227 */ 228 int cd_invert = 1; /* invert status of CD line - PPS support via CD input */ 229 230 #ifdef PARSEDEBUG 231 int parsedebug = ~0; 232 #else 233 int parsedebug = 0; 234 #endif 235 236 /*--------------- module implementation -----------------------------*/ 237 238 #define TIMEVAL_USADD(_X_, _US_) do {\ 239 (_X_)->tv_usec += (_US_);\ 240 if ((_X_)->tv_usec >= 1000000)\ 241 {\ 242 (_X_)->tv_sec++;\ 243 (_X_)->tv_usec -= 1000000;\ 244 }\ 245 } while (0) 246 247 static int init_linemon P((queue_t *)); 248 static void close_linemon P((queue_t *, queue_t *)); 249 250 #define M_PARSE 0x0001 251 #define M_NOPARSE 0x0002 252 253 void 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 const char *form, 268 ... 269 ) 270 { 271 va_list ap; 272 273 va_start(ap, form); 274 275 if (lev & parsedebug) 276 vcmn_err(CE_CONT, (char *)form, ap); 277 278 va_end(ap); 279 } 280 281 static int 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 ctime; 645 timespec_t hres_time; 646 647 /* 648 * get time on packet delivery 649 */ 650 gethrestime(&hres_time); 651 ctime.tv.tv_sec = hres_time.tv_sec; 652 ctime.tv.tv_usec = hres_time.tv_nsec / 1000; 653 654 if (!(parse->parse_status & PARSE_ENABLE)) 655 { 656 pprintf(DD_RPUT, "parse: parserput - parser disabled - forward type 0x%x\n", type); 657 if (canputnext(q) || (mp->b_datap->db_type > QPCTL)) 658 { 659 putnext(q, mp); 660 } 661 else 662 putq(q, mp); 663 } 664 else 665 { 666 pprintf(DD_RPUT, "parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK"); 667 if (type == M_DATA) 668 { 669 /* 670 * parse packet looking for start an end characters 671 */ 672 while (mp != (mblk_t *)NULL) 673 { 674 ch = rdchar(&mp); 675 if (ch != ~0 && parse_ioread(&parse->parse_io, (unsigned int)ch, &ctime)) 676 { 677 /* 678 * up up and away (hopefully ...) 679 * don't press it if resources are tight or nobody wants it 680 */ 681 nmp = (mblk_t *)NULL; 682 if (canputnext(parse->parse_queue) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) 683 { 684 bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); 685 nmp->b_wptr += sizeof(parsetime_t); 686 putnext(parse->parse_queue, nmp); 687 } 688 else 689 if (nmp) freemsg(nmp); 690 parse_iodone(&parse->parse_io); 691 } 692 } 693 } 694 else 695 { 696 if (parse_ioread(&parse->parse_io, (unsigned int)0, &ctime)) 697 { 698 /* 699 * up up and away (hopefully ...) 700 * don't press it if resources are tight or nobody wants it 701 */ 702 nmp = (mblk_t *)NULL; 703 if (canputnext(parse->parse_queue) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) 704 { 705 bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); 706 nmp->b_wptr += sizeof(parsetime_t); 707 putnext(parse->parse_queue, nmp); 708 } 709 else 710 if (nmp) freemsg(nmp); 711 parse_iodone(&parse->parse_io); 712 } 713 freemsg(mp); 714 } 715 break; 716 } 717 } 718 719 /* 720 * CD PPS support for non direct ISR hack 721 */ 722 case M_HANGUP: 723 case M_UNHANGUP: 724 { 725 register parsestream_t * parse = (parsestream_t *)q->q_ptr; 726 timestamp_t ctime; 727 timespec_t hres_time; 728 register mblk_t *nmp; 729 register int status = cd_invert ^ (type == M_UNHANGUP); 730 731 gethrestime(&hres_time); 732 ctime.tv.tv_sec = hres_time.tv_sec; 733 ctime.tv.tv_usec = hres_time.tv_nsec / 1000; 734 735 pprintf(DD_RPUT, "parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN"); 736 737 if ((parse->parse_status & PARSE_ENABLE) && 738 parse_iopps(&parse->parse_io, status ? SYNC_ONE : SYNC_ZERO, &ctime)) 739 { 740 nmp = (mblk_t *)NULL; 741 if (canputnext(parse->parse_queue) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) 742 { 743 bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); 744 nmp->b_wptr += sizeof(parsetime_t); 745 putnext(parse->parse_queue, nmp); 746 } 747 else 748 if (nmp) freemsg(nmp); 749 parse_iodone(&parse->parse_io); 750 freemsg(mp); 751 } 752 else 753 if (canputnext(q) || (mp->b_datap->db_type > QPCTL)) 754 { 755 putnext(q, mp); 756 } 757 else 758 putq(q, mp); 759 760 if (status) 761 { 762 parse->parse_ppsclockev.tv = ctime.tv; 763 ++(parse->parse_ppsclockev.serial); 764 } 765 } 766 } 767 return 0; 768 } 769 770 static int init_zs_linemon P((queue_t *, queue_t *)); /* handle line monitor for "zs" driver */ 771 static void close_zs_linemon P((queue_t *, queue_t *)); 772 773 /*-------------------- CD isr status monitor ---------------*/ 774 775 static int 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 P((struct zscom *)); /* zs external status interupt handler */ 853 854 /* 855 * there should be some docs telling how to get to 856 * sz:zs_usec_delay and zs:initzsops() 857 */ 858 #define zs_usec_delay 5 859 860 struct savedzsops 861 { 862 struct zsops zsops; 863 struct zsops *oldzsops; 864 }; 865 866 static struct zsops *emergencyzs; 867 868 static int 869 init_zs_linemon( 870 queue_t *q, 871 queue_t *my_q 872 ) 873 { 874 register struct zscom *zs; 875 register struct savedzsops *szs; 876 register parsestream_t *parsestream = (parsestream_t *)my_q->q_ptr; 877 /* 878 * we expect the zsaline pointer in the q_data pointer 879 * from there on we insert our on EXTERNAL/STATUS ISR routine 880 * into the interrupt path, before the standard handler 881 */ 882 zs = ((struct asyncline *)q->q_ptr)->za_common; 883 if (!zs) 884 { 885 /* 886 * well - not found on startup - just say no (shouldn't happen though) 887 */ 888 return 0; 889 } 890 else 891 { 892 /* 893 * we do a direct replacement, in case others fiddle also 894 * if somebody else grabs our hook and we disconnect 895 * we are in DEEP trouble - panic is likely to be next, sorry 896 */ 897 szs = (struct savedzsops *) kmem_alloc(sizeof(struct savedzsops), KM_SLEEP); 898 899 if (szs == (struct savedzsops *)0) 900 { 901 pprintf(DD_INSTALL, "init_zs_linemon: CD monitor NOT installed - no memory\n"); 902 903 return 0; 904 } 905 else 906 { 907 parsestream->parse_data = (void *)szs; 908 909 mutex_enter(zs->zs_excl); 910 911 parsestream->parse_dqueue = q; /* remember driver */ 912 913 szs->zsops = *zs->zs_ops; 914 szs->zsops.zsop_xsint = (void (*) P((struct zscom *)))zs_xsisr; /* place our bastard */ 915 szs->oldzsops = zs->zs_ops; 916 emergencyzs = zs->zs_ops; 917 918 zs->zs_ops = &szs->zsops; /* hook it up */ 919 /* 920 * XXX: this is usually done via zsopinit() 921 * - have yet to find a way to call that routine 922 */ 923 zs->zs_xsint = (void (*) P((struct zscom *)))zs_xsisr; 924 925 mutex_exit(zs->zs_excl); 926 927 pprintf(DD_INSTALL, "init_zs_linemon: CD monitor installed\n"); 928 929 return 1; 930 } 931 } 932 } 933 934 /* 935 * unregister our ISR routine - must call under splhigh() (or 936 * whatever block ZS status interrupts) 937 */ 938 static void 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) P((struct zscom *)); 1121 1122 /* 1123 * back home - phew (hopping along stream queues might 1124 * prove dangerous to your health) 1125 */ 1126 if ((zsisr = ((struct savedzsops *)((parsestream_t *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint)) 1127 zsisr(zs); 1128 else 1129 panic("zs_xsisr: unable to locate original ISR"); 1130 1131 pprintf(DD_ISR, "zs_xsisr: non CD event was processed for \"%s\"\n", dname); 1132 /* 1133 * now back to our program ... 1134 */ 1135 return; 1136 } 1137 } 1138 1139 q = q->q_next; 1140 1141 if (!loopcheck--) 1142 { 1143 panic("zs_xsisr: STREAMS Queue corrupted - non CD event"); 1144 } 1145 } 1146 1147 /* 1148 * last resort - shouldn't even come here as it indicates 1149 * corrupted TTY structures 1150 */ 1151 printf("zs_zsisr: looking for \"%s\" - found \"%s\" - taking EMERGENCY path\n", parseinfo.st_rdinit->qi_minfo->mi_idname, dname ? dname : "-NIL-"); 1152 1153 if (emergencyzs && emergencyzs->zsop_xsint) 1154 emergencyzs->zsop_xsint(zs); 1155 else 1156 panic("zs_xsisr: no emergency ISR handler"); 1157 } 1158 #endif /* sun */ 1159 1160 /* 1161 * History: 1162 * 1163 * parsesolaris.c,v 1164 * Revision 4.11 2005/04/16 17:32:10 kardel 1165 * update copyright 1166 * 1167 * Revision 4.10 2004/11/14 16:06:08 kardel 1168 * update Id tags 1169 * 1170 * Revision 4.9 2004/11/14 15:29:41 kardel 1171 * support PPSAPI, upgrade Copyright to Berkeley style 1172 * 1173 * Revision 4.6 1998/11/15 21:56:08 kardel 1174 * ntp_memset not necessary 1175 * 1176 * Revision 4.5 1998/11/15 21:23:37 kardel 1177 * ntp_memset() replicated in Sun kernel files 1178 * 1179 * Revision 4.4 1998/06/14 21:09:40 kardel 1180 * Sun acc cleanup 1181 * 1182 * Revision 4.3 1998/06/13 12:14:59 kardel 1183 * more prototypes 1184 * fix name clashes 1185 * allow for ansi2knr 1186 * 1187 * Revision 4.2 1998/06/12 15:23:08 kardel 1188 * fix prototypes 1189 * adjust for ansi2knr 1190 * 1191 * Revision 4.1 1998/05/24 09:38:46 kardel 1192 * streams initiated iopps calls (M_xHANGUP) are now consistent with the 1193 * respective calls from zs_xsisr() 1194 * simulation of CARRIER status to avoid unecessary M_xHANGUP messages 1195 * 1196 * Revision 4.0 1998/04/10 19:45:38 kardel 1197 * Start 4.0 release version numbering 1198 * 1199 * from V3 3.28 log info deleted 1998/04/11 kardel 1200 */ 1201