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