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