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