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