|
|
1.1 ! root 1: /* (-lgl ! 2: * COHERENT Driver Kit Version 1.1.0 ! 3: * Copyright (c) 1982, 1990 by Mark Williams Company. ! 4: * All rights reserved. May not be copied without permission. ! 5: -lgl) */ ! 6: /* ! 7: * Raw Serial Device Driver. ! 8: * ! 9: * Provides fast, efficiently buffered serial i/o to COM1 & COM2. ! 10: * Supports an extreme subset of System V (termio) parameters. ! 11: * c_iflag: ISTRIP, IXON, IXANY, IGNBRK, INPCK, PARMRK, IGNPAR. ! 12: * c_oflag: OPOST, ONLCR, ONLRET, TAB3. ! 13: * c_cflag: *. ! 14: * ! 15: */ ! 16: ! 17: #include <sys/coherent.h> ! 18: #include <sys/ins8250.h> ! 19: #include <sys/proc.h> ! 20: #include <sys/con.h> ! 21: #include <sys/devices.h> ! 22: #include <sys/sched.h> ! 23: #include <sys/stat.h> ! 24: #include <termio.h> ! 25: #include <errno.h> ! 26: ! 27: #define COM1VEC 4 /* interrupt vector for COM1 */ ! 28: #define COM2VEC 3 /* interrupt vector for COM2 */ ! 29: ! 30: #define COM1PORT 0x3F8 /* i/o port address for COM1 */ ! 31: #define COM2PORT 0x2F8 /* i/o port address for COM2 */ ! 32: ! 33: #ifdef RS1 ! 34: # define CFLAG RS1CFLAG ! 35: # define MAJ AL1_MAJOR /* major device for /dev/rs1 */ ! 36: # define rscon rs1con /* configuration table for " */ ! 37: # define rstty rs1tty ! 38: # define IVEC COM2VEC /* interrupt vector for rs1 */ ! 39: # define PORT COM2PORT /* i/o port address for rs1 */ ! 40: #else ! 41: # define CFLAG RS0CFLAG ! 42: # define MAJ AL0_MAJOR /* major device for /dev/rs0 */ ! 43: # define rscon rs0con /* configuration table for " */ ! 44: # define rstty rs0tty ! 45: # define IVEC COM1VEC /* interrupt vector for rs0 */ ! 46: # define PORT COM1PORT /* i/o port address for rs0 */ ! 47: #endif ! 48: ! 49: #define CTRLS '\023' ! 50: #define CTRLQ '\021' ! 51: ! 52: /* ! 53: * Functions. ! 54: */ ! 55: ! 56: int rsload(); ! 57: int rsunload(); ! 58: int rsopen(); ! 59: int rsclose(); ! 60: int rsread(); ! 61: int rswrite(); ! 62: int rsioctl(); ! 63: int rspoll(); ! 64: int nulldev(); ! 65: int nonedev(); ! 66: ! 67: int rsintr(); ! 68: int rsparam(); ! 69: ! 70: /* ! 71: * Configuration table. ! 72: */ ! 73: ! 74: CON rscon ={ ! 75: DFCHR|DFPOL, /* Flags */ ! 76: MAJ, /* Major index */ ! 77: rsopen, /* Open */ ! 78: rsclose, /* Close */ ! 79: nulldev, /* Block */ ! 80: rsread, /* Read */ ! 81: rswrite, /* Write */ ! 82: rsioctl, /* Ioctl */ ! 83: nulldev, /* Powerfail */ ! 84: nulldev, /* Timeout */ ! 85: rsload, /* Load */ ! 86: rsunload, /* Unload */ ! 87: rspoll /* Poll */ ! 88: }; ! 89: ! 90: /* ! 91: * Terminal structure. ! 92: */ ! 93: ! 94: #define RAWSZ (2048-1) ! 95: #define OUTSZ (2048-1) ! 96: ! 97: #define NRAWC ((rsrawq.rq_ix - rsrawq.rq_ox) & RAWSZ) ! 98: #define NOUTC ((rsoutq.rq_ix - rsoutq.rq_ox) & OUTSZ) ! 99: ! 100: #define TTSTOP 00001 ! 101: #define TTSBRK 00002 ! 102: #define CARRIER 00004 ! 103: ! 104: typedef ! 105: struct rawtty_s { ! 106: unsigned rt_state; /* terminal state */ ! 107: int rt_group; /* controlling process group */ ! 108: unsigned rt_ticks; /* send break 1/10 sec counter */ ! 109: unsigned rt_iflag; /* termio input flags */ ! 110: unsigned rt_oflag; /* termio output flags */ ! 111: unsigned rt_cflag; /* termio control flags */ ! 112: unsigned char rt_col; /* current output column */ ! 113: unsigned char rt_refc; /* # procs accessing the port */ ! 114: unsigned char rt_irefc; /* # procs waiting for input */ ! 115: unsigned char rt_orefc; /* # procs waitint for output */ ! 116: unsigned char rt_crefc; /* # procs waiting for carrier */ ! 117: unsigned char rt_drefc; /* # procs waiting for drain */ ! 118: event_t rt_ipolls; /* Procs polling on input queue */ ! 119: event_t rt_opolls; /* Procs polling on output que */ ! 120: } RAWTTY; ! 121: ! 122: typedef ! 123: struct iring_s { ! 124: unsigned short rq_mask; ! 125: unsigned short rq_ix; ! 126: unsigned short rq_ox; ! 127: unsigned char rq_cc[RAWSZ+1]; ! 128: } IRING; ! 129: ! 130: typedef ! 131: struct oring_s { ! 132: unsigned short rq_mask; ! 133: unsigned short rq_ix; ! 134: unsigned short rq_ox; ! 135: unsigned char rq_cc[OUTSZ+1]; ! 136: } ORING; ! 137: ! 138: /* ! 139: * Local variables. ! 140: */ ! 141: unsigned CFLAG = CLOCAL | CREAD | B1200 | CS8 | HUPCL; ! 142: RAWTTY rstty; ! 143: static ORING rsoutq; ! 144: static IRING rsrawq; ! 145: static TIM rstim; ! 146: ! 147: /* ! 148: * Time constant table. ! 149: * Indexed by ioctl baud rate. ! 150: */ ! 151: static ! 152: int timeconst[] = { ! 153: 0, /* 0 */ ! 154: 2304, /* 50 */ ! 155: 1536, /* 75 */ ! 156: 1047, /* 110 */ ! 157: 857, /* 134.5 */ ! 158: 768, /* 150 */ ! 159: 576, /* 200 */ ! 160: 384, /* 300 */ ! 161: 192, /* 600 */ ! 162: 96, /* 1200 */ ! 163: 64, /* 1800 */ ! 164: 48, /* 2400 */ ! 165: 24, /* 4800 */ ! 166: 12, /* 9600 */ ! 167: 6, /* 19200/EXTA */ ! 168: 6 /* 19200/EXTB */ ! 169: }; ! 170: ! 171: /* ! 172: * Rsload() -- Raw Serial Load Routine. ! 173: * ! 174: * Action: Define terminal parameters. ! 175: * Initialize terminal hardware. ! 176: * If serial port exists, seize its interrupt vector. ! 177: * ! 178: * Return: None. ! 179: */ ! 180: ! 181: static ! 182: rsload() ! 183: { ! 184: /* ! 185: * Initialize terminal parameters. ! 186: */ ! 187: rsoutq.rq_mask = OUTSZ; ! 188: rsrawq.rq_mask = RAWSZ; ! 189: ! 190: /* ! 191: * Initialize terminal hardware. ! 192: */ ! 193: rsparam(); ! 194: ! 195: /* ! 196: * If serial port exists, initialize interrupt vector. ! 197: */ ! 198: if ( inb(PORT+IER) == 0 ) { ! 199: setivec( IVEC, rsintr); ! 200: rscycle(); ! 201: } ! 202: } ! 203: ! 204: /* ! 205: * Rsunload() -- Raw Serial unload Routine. ! 206: */ ! 207: ! 208: static ! 209: rsunload() ! 210: { ! 211: timeout( &rstim, 0, NULL, 0 ); /* cancel timed function */ ! 212: clrivec( IVEC ); /* release interrupt vector */ ! 213: outb(PORT+IER, 0); /* disable port interrupts */ ! 214: outb(PORT+MCR, MC_OUT2); /* hangup port */ ! 215: } ! 216: ! 217: /* ! 218: * Rsopen -- Open Routine. ! 219: * ! 220: * Input: dev = device to open. ! 221: * If high bit (0x80) set in minor, modem control is requested. ! 222: * ! 223: * Action: Validate minor device. ! 224: * Increment reference count. ! 225: * If first reference and parameters are not initialized, ! 226: * set default parameters and initialize hardware. ! 227: * ! 228: * Return: None. ! 229: */ ! 230: ! 231: static ! 232: rsopen( dev, mode ) ! 233: ! 234: dev_t dev; ! 235: ! 236: { ! 237: register PROC *pp = SELF; ! 238: ! 239: /* ! 240: * Validate minor device. ! 241: */ ! 242: if (minor(dev) & ~0x80) { ! 243: u.u_error = ENODEV; ! 244: return; ! 245: } ! 246: ! 247: /* ! 248: * Validate hardware. ! 249: */ ! 250: if (inb(PORT+IER) & ~(IE_RxI|IE_TxI|IE_LSI)) { ! 251: u.u_error = ENXIO; ! 252: return; ! 253: } ! 254: ! 255: /* ! 256: * Ensure controlling terminal and group fields initialized. ! 257: */ ! 258: if (pp->p_ttdev == NODEV) ! 259: pp->p_ttdev = dev; ! 260: if (pp->p_group == 0) ! 261: pp->p_group = pp->p_pid; ! 262: ! 263: /* ! 264: * Check for first open. ! 265: */ ! 266: if (++rstty.rt_refc == 1) { ! 267: ! 268: if (pp->p_group == pp->p_pid) ! 269: rstty.rt_group = pp->p_group; ! 270: ! 271: if ((rstty.rt_cflag & CBAUD) == B0) { ! 272: ! 273: /* ! 274: * Define terminal parameters. ! 275: */ ! 276: rstty.rt_state = 0; ! 277: rstty.rt_col = 0; ! 278: rstty.rt_iflag = ISTRIP | IXON; ! 279: rstty.rt_oflag = OPOST | ONLCR | TAB3; ! 280: rstty.rt_cflag = CFLAG; ! 281: if ( minor(dev) & 0x80 ) ! 282: rstty.rt_cflag &= ~CLOCAL; ! 283: ! 284: /* ! 285: * Initialize terminal hardware. ! 286: */ ! 287: rsparam(); ! 288: } ! 289: ! 290: /* ! 291: * Discard input data. ! 292: */ ! 293: rsrawq.rq_ox = rsrawq.rq_ix; ! 294: } ! 295: ! 296: /* ! 297: * If modem control is requested, check carrier. ! 298: */ ! 299: if ( minor(dev) & 0x80 ) { ! 300: ! 301: /* ! 302: * Delay until carrier is present. ! 303: */ ! 304: while ( (rstty.rt_state & CARRIER) == 0 ) { ! 305: ! 306: /* ! 307: * Sleep on carrier. ! 308: */ ! 309: ++rstty.rt_crefc; ! 310: sleep( &rstty.rt_crefc, ! 311: CVTTOUT, IVTTOUT, SVTTOUT); ! 312: --rstty.rt_crefc; ! 313: ! 314: /* ! 315: * Abort if non-ignored signal is received. ! 316: */ ! 317: if (SELF->p_ssig && nondsig()) { ! 318: ! 319: if (--rstty.rt_refc == 0) { ! 320: rstty.rt_group = 0; ! 321: rstty.rt_cflag = 0; ! 322: rsparam(); ! 323: } ! 324: u.u_error = EINTR; ! 325: return; ! 326: } ! 327: } ! 328: } ! 329: } ! 330: ! 331: /* ! 332: * Rsclose -- Close Routine. ! 333: * ! 334: * Action: Decrement reference count. ! 335: * If serial port is no longer referenced, ! 336: * and the hangup on last close bit is set in rt_cflag, ! 337: * clear terminal parameters, and initialize hardware. ! 338: * ! 339: * Return: None. ! 340: * ! 341: * Note: This routine does not wait for the output queue to empty. ! 342: */ ! 343: ! 344: static ! 345: rsclose( dev ) ! 346: ! 347: dev_t dev; ! 348: ! 349: { ! 350: /* ! 351: * Check for last close and hangup on close. ! 352: */ ! 353: if ((rstty.rt_refc == 1) && (rstty.rt_cflag & HUPCL)) { ! 354: ! 355: /* ! 356: * Wait for output to drain. ! 357: */ ! 358: while ( rsoutq.rq_ox != rsoutq.rq_ix ) { ! 359: ! 360: ++rstty.rt_drefc; ! 361: sleep( &rstty.rt_drefc, CVTTOUT, IVTTOUT, SVTTOUT ); ! 362: --rstty.rt_drefc; ! 363: ! 364: if (rstty.rt_refc != 1) { ! 365: rstty.rt_refc--; ! 366: return; ! 367: } ! 368: ! 369: if (SELF->p_ssig && nondsig()) ! 370: break; ! 371: } ! 372: ! 373: /* ! 374: * Initialize terminal hardware. ! 375: */ ! 376: rstty.rt_group = 0; ! 377: rstty.rt_cflag = 0; ! 378: rsparam(); ! 379: ! 380: /* ! 381: * Flush input and output queues. ! 382: */ ! 383: rsrawq.rq_ix = ! 384: rsrawq.rq_ox = ! 385: rsoutq.rq_ox = ! 386: rsoutq.rq_ix = 0; ! 387: } ! 388: --rstty.rt_refc; ! 389: } ! 390: ! 391: /* ! 392: * Rsread -- Read Routine. ! 393: * ! 394: * Input: iop = pointer to structure containing i/o parameters. ! 395: * ! 396: * Action: Attempt to read data from input buffer until at least ! 397: * one character has been read, or a signal is received ! 398: * by the current process. ! 399: * Update the parameters in the io structure. ! 400: * If a signal is received, set errno to EINTR. ! 401: * ! 402: * Return: None. ! 403: */ ! 404: ! 405: static ! 406: rsread( dev, iop ) ! 407: ! 408: dev_t dev; ! 409: register IO *iop; ! 410: ! 411: { ! 412: register int sioc; ! 413: ! 414: /* ! 415: * Remember original char count. ! 416: */ ! 417: sioc = iop->io_ioc; ! 418: ! 419: do { ! 420: /* ! 421: * Transfer data until done or input buffer empty. ! 422: */ ! 423: rsin( &rsrawq, iop ); ! 424: ! 425: /* ! 426: * Return if some data was transferred. ! 427: */ ! 428: if (sioc != iop->io_ioc) ! 429: return; ! 430: ! 431: /* ! 432: * Non-blocking reads. ! 433: */ ! 434: if ( iop->io_flag & IONDLY ) { ! 435: u.u_error = EAGAIN; ! 436: return; ! 437: } ! 438: ! 439: /* ! 440: * Sleep waiting for a signal or input data. ! 441: */ ! 442: ++rstty.rt_irefc; ! 443: sleep( &rstty.rt_irefc, CVTTOUT, IVTTOUT, SVTTOUT ); ! 444: --rstty.rt_irefc; ! 445: ! 446: /* ! 447: * Abort if a non-ignored signal was received. ! 448: */ ! 449: if (SELF->p_ssig && nondsig()) { ! 450: u.u_error = EINTR; ! 451: return; ! 452: } ! 453: ! 454: } while (1); ! 455: } ! 456: ! 457: /* ! 458: * Rswrite -- Write Routine. ! 459: */ ! 460: ! 461: static ! 462: rswrite( dev, iop ) ! 463: ! 464: dev_t dev; ! 465: register IO *iop; ! 466: ! 467: { ! 468: register int n; ! 469: ! 470: /* ! 471: * Non-blocking write. ! 472: */ ! 473: if ( iop->io_flag & IONDLY ) { ! 474: ! 475: /* ! 476: * Calculate free slots. ! 477: */ ! 478: n = rsoutq.rq_mask - rsoutq.rq_ix + rsoutq.rq_ox; ! 479: n &= rsoutq.rq_mask; ! 480: ! 481: /* ! 482: * Insufficient space. ! 483: */ ! 484: if ( n <= iop->io_ioc ) { ! 485: u.u_error = EAGAIN; ! 486: return; ! 487: } ! 488: } ! 489: ! 490: do { ! 491: /* ! 492: * Transfer data until done or output queue full. ! 493: */ ! 494: rsout( &rsoutq, iop ); ! 495: ! 496: /* ! 497: * Make sure the transmitter is operating. ! 498: */ ! 499: rsstart(); ! 500: ! 501: /* ! 502: * Return if all data was transferred. ! 503: */ ! 504: if ( iop->io_ioc == 0 ) ! 505: return; ! 506: ! 507: /* ! 508: * Sleep waiting for a signal or room in the output queue. ! 509: */ ! 510: ++rstty.rt_orefc; ! 511: sleep( &rstty.rt_orefc, CVTTOUT, IVTTOUT, SVTTOUT ); ! 512: --rstty.rt_orefc; ! 513: ! 514: /* ! 515: * Abort if a non-ignored signal was received. ! 516: */ ! 517: if ( SELF->p_ssig && nondsig() ) { ! 518: u.u_error = EINTR; ! 519: return; ! 520: } ! 521: ! 522: } while (1); ! 523: } ! 524: ! 525: /* ! 526: * Rspoll -- Polling Routine. ! 527: */ ! 528: static int ! 529: rspoll( dev, ev, msec ) ! 530: dev_t dev; ! 531: register int ev; ! 532: int msec; ! 533: { ! 534: /* ! 535: * No priority reports. ! 536: */ ! 537: ev &= ~POLLPRI; ! 538: ! 539: /* ! 540: * Input poll with empty input ring. ! 541: */ ! 542: if ( (ev & POLLIN) && (rsrawq.rq_ix == rsrawq.rq_ox) ) { ! 543: ! 544: /* ! 545: * Blocking input poll. ! 546: */ ! 547: if ( msec != 0 ) ! 548: pollopen( &rstty.rt_ipolls ); ! 549: ! 550: /* ! 551: * Second look and clear input report. ! 552: */ ! 553: if ( rsrawq.rq_ix == rsrawq.rq_ox ) ! 554: ev &= ~POLLIN; ! 555: } ! 556: ! 557: /* ! 558: * Output poll with non-empty output ring. ! 559: */ ! 560: if ( (ev & POLLOUT) && (rsoutq.rq_ix != rsrawq.rq_ox) ) { ! 561: ! 562: /* ! 563: * Blocking output poll. ! 564: */ ! 565: if ( msec != 0 ) ! 566: pollopen( &rstty.rt_opolls ); ! 567: ! 568: /* ! 569: * Second look and clear output report. ! 570: */ ! 571: if ( rsoutq.rq_ix != rsoutq.rq_ox ) ! 572: ev &= ~POLLOUT; ! 573: } ! 574: ! 575: return ev; ! 576: } ! 577: ! 578: /* ! 579: * Cyclic [1 sec] Routine. ! 580: */ ! 581: static ! 582: rscycle() ! 583: { ! 584: register PROC *pp; ! 585: register int b; ! 586: ! 587: /* ! 588: * Check for carrier transitions. ! 589: */ ! 590: if ( inb( PORT + MSR ) & MS_RLSD ) { ! 591: ! 592: /* ! 593: * Have carrier. Wake processes waiting for carrier. ! 594: */ ! 595: rstty.rt_state |= CARRIER; ! 596: ! 597: if ( rstty.rt_crefc ) ! 598: wakeup( &rstty.rt_crefc ); ! 599: } ! 600: else if ((rstty.rt_state & CARRIER) && (rstty.rt_cflag&CLOCAL) == 0) { ! 601: ! 602: /* ! 603: * Lost carrier. Signal attached processes. ! 604: */ ! 605: rstty.rt_state &= ~CARRIER; ! 606: ! 607: if (rstty.rt_refc && (b = rstty.rt_group)) ! 608: for (pp=procq.p_nforw; pp != &procq; pp=pp->p_nforw) ! 609: if ( pp->p_group == b ) ! 610: sendsig( SIGHUP, pp ); ! 611: } ! 612: ! 613: /* ! 614: * Wakeup processes waiting to read if input data present. ! 615: */ ! 616: if ( rsrawq.rq_ix != rsrawq.rq_ox ) { ! 617: if ( rstty.rt_irefc ) ! 618: wakeup( &rstty.rt_irefc ); ! 619: if ( rstty.rt_ipolls.e_procp ) ! 620: pollwake( &rstty.rt_ipolls ); ! 621: } ! 622: ! 623: /* ! 624: * Check for break being sent. ! 625: */ ! 626: if ( rstty.rt_ticks != 0 ) { ! 627: ! 628: if ( --rstty.rt_ticks == 0 ) { ! 629: ! 630: b = inb( PORT + LCR ); ! 631: outb( PORT + LCR, b & ~LC_SBRK ); ! 632: rstty.rt_state &= ~TTSBRK; ! 633: } ! 634: } ! 635: ! 636: /* ! 637: * Can check output if not sending break. ! 638: */ ! 639: if ( rstty.rt_ticks == 0 ) { ! 640: ! 641: /* ! 642: * Restart output if necessary. ! 643: */ ! 644: if ( rsoutq.rq_ox != rsoutq.rq_ix ) ! 645: rsstart(); ! 646: ! 647: /* ! 648: * Wakeup processes waiting for drain if output queue empty. ! 649: */ ! 650: if ( rstty.rt_drefc ) { ! 651: if ( rsoutq.rq_ix == rsoutq.rq_ox ) ! 652: wakeup( &rstty.rt_drefc ); ! 653: } ! 654: ! 655: /* ! 656: * Wakeup processes waiting to write if 512 slots are free. ! 657: */ ! 658: else if ( NOUTC < OUTSZ-512 ) { ! 659: if ( rstty.rt_orefc ) ! 660: wakeup( &rstty.rt_orefc ); ! 661: if ( rstty.rt_opolls.e_procp ) ! 662: pollwake( &rstty.rt_opolls ); ! 663: } ! 664: } ! 665: ! 666: timeout( &rstim, HZ/10, rscycle, 0 ); ! 667: } ! 668: ! 669: /* ! 670: * Rsintr -- Serial Interrupt Handler. ! 671: * ! 672: * Action: Process all pending interrupt service requests ! 673: * on the serial port. ! 674: * ! 675: * Return: None. ! 676: * ! 677: * Notes: This routine must loop until all requests are serviced ! 678: * because of the edge sensitive nature of the programmable ! 679: * interrupt controller. ! 680: */ ! 681: ! 682: static ! 683: rsintr() ! 684: { ! 685: register int b; ! 686: ! 687: /* ! 688: * Service serial port interrupt requests, highest to lowest priority. ! 689: */ ! 690: rescan: ! 691: b = inb( PORT + IIR ); ! 692: ! 693: switch ( b ) { ! 694: ! 695: case LS_INTR: ! 696: /* ! 697: * Get line status (clear interrupt). ! 698: */ ! 699: b = inb( PORT + LSR ); ! 700: ! 701: /* ! 702: * Check for received break. ! 703: */ ! 704: if (b & LS_BREAK) { ! 705: ! 706: /* ! 707: * Read the break char ('\0'). ! 708: */ ! 709: rsrawq.rq_cc[ rsrawq.rq_ix ] = inb( PORT + DREG ); ! 710: ! 711: /* ! 712: * Clear output stops. ! 713: */ ! 714: rstty.rt_state &= ~TTSTOP; ! 715: ! 716: /* ! 717: * Update input index if not ignoring break. ! 718: */ ! 719: if ((rstty.rt_iflag & IGNBRK) == 0) { ! 720: rsrawq.rq_ix ++; ! 721: rsrawq.rq_ix &= RAWSZ; ! 722: } ! 723: } ! 724: ! 725: /* ! 726: * Special handling if frame/parity error and checking enabled. ! 727: */ ! 728: if ((b & (LS_FRAME|LS_PARITY)) && (rstty.rt_iflag & INPCK)) { ! 729: ! 730: /* ! 731: * Ignore next input char if IGNPAR set. ! 732: */ ! 733: if (rstty.rt_iflag & IGNPAR) ! 734: inb( PORT + DREG ); ! 735: /* ! 736: * Change next input char into 0377,0,ch if PARMRK set. ! 737: */ ! 738: else if (rstty.rt_iflag & PARMRK) { ! 739: ! 740: b = rsrawq.rq_ix; ! 741: rsrawq.rq_cc[ b++ ] = 0377; ! 742: b &= RAWSZ; ! 743: rsrawq.rq_cc[ b++ ] = '\0'; ! 744: b &= RAWSZ; ! 745: rsrawq.rq_cc[ b++ ] = inb( PORT + DREG ); ! 746: b &= RAWSZ; ! 747: rsrawq.rq_ix = b; ! 748: } ! 749: ! 750: /* ! 751: * Otherwise change next input char into null. ! 752: */ ! 753: else { ! 754: inb( PORT + DREG ); ! 755: rsrawq.rq_cc[ rsrawq.rq_ix++ ] = '\0'; ! 756: rsrawq.rq_ix &= RAWSZ; ! 757: } ! 758: } ! 759: goto rescan; ! 760: ! 761: case Rx_INTR: ! 762: /* ! 763: * Read character from receive buffer. ! 764: */ ! 765: b = inb( PORT + DREG ); ! 766: ! 767: /* ! 768: * Discard high bit if ISTRIP set. ! 769: */ ! 770: if ( rstty.rt_iflag & ISTRIP ) ! 771: b &= 0177; ! 772: ! 773: /* ! 774: * Check for output flow control if IXON set. ! 775: */ ! 776: if ( rstty.rt_iflag & IXON ) { ! 777: ! 778: /* ! 779: * Stop output if Ctl-S. ! 780: */ ! 781: if ( b == CTRLS ) { ! 782: rstty.rt_state |= TTSTOP; ! 783: goto rescan; ! 784: } ! 785: ! 786: /* ! 787: * Resume output if Ctl-Q. ! 788: */ ! 789: if ( b == CTRLQ ) { ! 790: rstty.rt_state &= ~TTSTOP; ! 791: goto rescan; ! 792: } ! 793: ! 794: /* ! 795: * Enable output if IXANY set. ! 796: */ ! 797: if ( rstty.rt_iflag & IXANY ) ! 798: rstty.rt_state &= ~TTSTOP; ! 799: } ! 800: ! 801: /* ! 802: * Save the character in the input queue. ! 803: */ ! 804: rsrawq.rq_cc[ rsrawq.rq_ix++ ] = b; ! 805: rsrawq.rq_ix &= RAWSZ; ! 806: ! 807: /* ! 808: * Save again if 0377 and parity marking enabled. ! 809: */ ! 810: if ((b == 0377) ! 811: && ((rstty.rt_iflag & (INPCK|PARMRK)) == (INPCK|PARMRK))) { ! 812: ! 813: rsrawq.rq_cc[ rsrawq.rq_ix++ ] = b; ! 814: rsrawq.rq_ix &= RAWSZ; ! 815: } ! 816: ! 817: goto rescan; ! 818: ! 819: case Tx_INTR: ! 820: rsstart(); ! 821: goto rescan; ! 822: } ! 823: } ! 824: ! 825: /* ! 826: * Rsstart() ! 827: * ! 828: * Action: While output data is available, and the transmitter buffer ! 829: * is empty, transfer one character from the output queue to the ! 830: * transmit buffer. ! 831: * ! 832: * Return: None. ! 833: */ ! 834: ! 835: static ! 836: rsstart() ! 837: { ! 838: register int b; ! 839: register int s; ! 840: ! 841: /* ! 842: * Can't transmit if output stopped or sending break. ! 843: */ ! 844: if ( rstty.rt_state & (TTSTOP|TTSBRK) ) ! 845: return; ! 846: ! 847: /* ! 848: * Can't transmit if modem control enabled without CTS present. ! 849: */ ! 850: if ( (rstty.rt_cflag & CLOCAL) == 0 ) ! 851: if ( (inb(PORT+MSR) & MS_CTS) == 0 ) ! 852: return; ! 853: ! 854: /* ! 855: * Disable interrupts to avoid critical race. ! 856: */ ! 857: s = sphi(); ! 858: ! 859: /* ! 860: * Can transmit if output data available and transmit buffer empty. ! 861: */ ! 862: if ( (rsoutq.rq_ix != rsoutq.rq_ox) ! 863: && (inb(PORT+LSR) & LS_TxRDY) ) { ! 864: ! 865: /* ! 866: * Get next char from output queue. ! 867: */ ! 868: b = rsoutq.rq_cc [ rsoutq.rq_ox ]; ! 869: ! 870: if (rstty.rt_oflag & OPOST) { ! 871: ! 872: /* ! 873: * Printable characters increment the column. ! 874: */ ! 875: if (b >= ' ') { ! 876: rstty.rt_col++; ! 877: } ! 878: /* ! 879: * Carriage return resets the column. ! 880: */ ! 881: else if (b == '\r') { ! 882: rstty.rt_col = 0; ! 883: if (rstty.rt_oflag & OCRNL) ! 884: b = '\n'; ! 885: } ! 886: /* ! 887: * New-line may also generate a carriage return. ! 888: */ ! 889: else if (b == '\n') { ! 890: if (rstty.rt_oflag & ONLCR) { ! 891: if (rstty.rt_col) { ! 892: rstty.rt_col = 0; ! 893: rsoutq.rq_ox--; ! 894: b = '\r'; ! 895: } ! 896: } ! 897: else if (rstty.rt_oflag & ONLRET) ! 898: rstty.rt_col = 0; ! 899: } ! 900: /* ! 901: * Backspace decrements the column. ! 902: */ ! 903: else if (b == '\b') { ! 904: if (rstty.rt_col) ! 905: --rstty.rt_col; ! 906: } ! 907: /* ! 908: * Tabs may generate spaces, always move to tab stop. ! 909: */ ! 910: else if (b == '\t') { ! 911: if ((rstty.rt_oflag & TABDLY) == TAB3) { ! 912: b = ' '; ! 913: if (++rstty.rt_col & 7) ! 914: rsoutq.rq_ox--; ! 915: } ! 916: else { ! 917: rstty.rt_col |= 7; ! 918: rstty.rt_col++; ! 919: } ! 920: } ! 921: } ! 922: rsoutq.rq_ox++; ! 923: rsoutq.rq_ox &= OUTSZ; ! 924: ! 925: /* ! 926: * Transmit next char. ! 927: */ ! 928: outb( PORT+DREG, b ); ! 929: } ! 930: ! 931: spl(s); ! 932: } ! 933: ! 934: /* ! 935: * Ioctl Routine. ! 936: */ ! 937: ! 938: static ! 939: rsioctl( dev, com, vec ) ! 940: ! 941: dev_t dev; ! 942: int com; ! 943: struct termio *vec; ! 944: ! 945: { ! 946: register int b; ! 947: struct termio tb; ! 948: ! 949: switch (com) { ! 950: ! 951: case TCSETAW: /* Set attributes after waiting for output to clear */ ! 952: case TCSETAF: /* ditto, but also flush input queue */ ! 953: case TCSBRK: /* wait for output to clear, send break */ ! 954: ! 955: /* ! 956: * Delay until output queue is empty. ! 957: */ ! 958: while ( rsoutq.rq_ox != rsoutq.rq_ix ) { ! 959: ! 960: /* ! 961: * Sleep waiting for empty output queue. ! 962: */ ! 963: ++rstty.rt_drefc; ! 964: sleep( &rstty.rt_drefc, CVTTOUT, IVTTOUT, SVTTOUT); ! 965: --rstty.rt_drefc; ! 966: ! 967: /* ! 968: * Abort if a non-ignored signal was received. ! 969: */ ! 970: if ( SELF->p_ssig && nondsig() ) { ! 971: u.u_error = EINTR; ! 972: return; ! 973: } ! 974: } ! 975: ! 976: if ( com == TCSBRK ) { ! 977: ! 978: b = inb( PORT + LCR ); ! 979: ! 980: if ( vec == 0 ) { ! 981: rstty.rt_ticks = 3; /* 0.2 to 0.3 sec */ ! 982: rstty.rt_state |= TTSBRK; ! 983: b |= LC_SBRK; ! 984: } ! 985: else { ! 986: rstty.rt_ticks = 0; ! 987: rstty.rt_state &= ~TTSBRK; ! 988: b &= ~LC_SBRK; ! 989: } ! 990: ! 991: outb( PORT + LCR, b ); ! 992: return; ! 993: } ! 994: /* no break */ ! 995: ! 996: case TCSETA: ! 997: /* ! 998: * Get new terminal attributes. ! 999: */ ! 1000: ukcopy( vec, &tb, sizeof(tb) ); ! 1001: if ( u.u_error ) ! 1002: return; ! 1003: ! 1004: /* ! 1005: * Set terminal attributes and hardware. ! 1006: */ ! 1007: rstty.rt_iflag = tb.c_iflag; ! 1008: rstty.rt_oflag = tb.c_oflag; ! 1009: if (rstty.rt_cflag != tb.c_cflag) { ! 1010: rstty.rt_cflag = tb.c_cflag; ! 1011: rsparam(); ! 1012: } ! 1013: ! 1014: if ((rstty.rt_iflag & IXON) == 0) ! 1015: rstty.rt_state &= ~TTSTOP; ! 1016: ! 1017: /* ! 1018: * Flush input queue if command was TCSETAF. ! 1019: */ ! 1020: if ( com == TCSETAF ) ! 1021: rsrawq.rq_ox = rsrawq.rq_ix; ! 1022: break; ! 1023: ! 1024: case TCGETA: /* Get terminal attributes */ ! 1025: ! 1026: memset( &tb, 0, sizeof(tb) ); ! 1027: tb.c_cflag = rstty.rt_cflag; ! 1028: tb.c_iflag = rstty.rt_iflag; ! 1029: tb.c_oflag = rstty.rt_oflag; ! 1030: ! 1031: /* ! 1032: * Transfer terminal attributes to user space. ! 1033: */ ! 1034: kucopy( &tb, vec, sizeof(tb) ); ! 1035: break; ! 1036: ! 1037: case TCFLSH: ! 1038: switch ((int) vec) { ! 1039: case 0: ! 1040: /* flush input queue */ ! 1041: rsrawq.rq_ox = rsrawq.rq_ix; ! 1042: break; ! 1043: case 1: ! 1044: /* flush output queue */ ! 1045: rsoutq.rq_ox = rsoutq.rq_ix; ! 1046: break; ! 1047: case 2: ! 1048: /* flush both input and output queues */ ! 1049: rsrawq.rq_ox = rsrawq.rq_ix; ! 1050: rsoutq.rq_ox = rsoutq.rq_ix; ! 1051: break; ! 1052: default: ! 1053: u.u_error = EINVAL; ! 1054: } ! 1055: break; ! 1056: ! 1057: case TCXONC: ! 1058: switch ( (int) vec ) { ! 1059: case 0: ! 1060: /* stop output */ ! 1061: rstty.rt_state |= TTSTOP; ! 1062: break; ! 1063: case 1: ! 1064: /* restart output */ ! 1065: rstty.rt_state &= ~TTSTOP; ! 1066: rsstart(); ! 1067: break; ! 1068: default: ! 1069: u.u_error = EINVAL; ! 1070: } ! 1071: break; ! 1072: ! 1073: default: ! 1074: u.u_error = EINVAL; ! 1075: } ! 1076: } ! 1077: ! 1078: /* ! 1079: * Rsparam -- Setup hardware parameters. ! 1080: */ ! 1081: ! 1082: static ! 1083: rsparam() ! 1084: { ! 1085: register int b; ! 1086: register int s; ! 1087: ! 1088: /* ! 1089: * Disable interrupts. ! 1090: */ ! 1091: s = sphi(); ! 1092: ! 1093: /* ! 1094: * Assert required modem control lines (DTR, RTS). ! 1095: */ ! 1096: if ((rstty.rt_cflag & CBAUD) == B0) ! 1097: outb( PORT+MCR, MC_OUT2 ); ! 1098: else if ((rstty.rt_refc == 0) && (rstty.rt_cflag & HUPCL)) ! 1099: outb( PORT+MCR, MC_OUT2 ); ! 1100: else ! 1101: outb( PORT+MCR, MC_OUT2+MC_DTR+MC_RTS ); ! 1102: ! 1103: /* ! 1104: * Program baud rate. ! 1105: */ ! 1106: if (b = timeconst[ rstty.rt_cflag & CBAUD ]) { ! 1107: outb( PORT+LCR, LC_DLAB ); ! 1108: outb( PORT+DLL, b ); ! 1109: outb( PORT+DLH, b >> 8 ); ! 1110: } ! 1111: ! 1112: /* ! 1113: * Program character size, parity, and stop bits. ! 1114: */ ! 1115: switch (rstty.rt_cflag & CSIZE) { ! 1116: case CS5: b = LC_CS5; break; ! 1117: case CS6: b = LC_CS6; break; ! 1118: case CS7: b = LC_CS7; break; ! 1119: case CS8: b = LC_CS8; break; ! 1120: } ! 1121: ! 1122: switch (rstty.rt_cflag & (PARENB|PARODD)) { ! 1123: case PARENB: b |= LC_PARENB|LC_PAREVEN; break; ! 1124: case PARENB|PARODD: b |= LC_PARENB; break; ! 1125: } ! 1126: ! 1127: if (rstty.rt_cflag & CSTOPB) ! 1128: b |= LC_STOPB; ! 1129: ! 1130: if (rstty.rt_state & TTSBRK) ! 1131: b |= LC_SBRK; ! 1132: ! 1133: outb( PORT+LCR, b ); ! 1134: ! 1135: /* ! 1136: * Enable desired interrupts. ! 1137: */ ! 1138: b = 0; ! 1139: if (rstty.rt_cflag & CBAUD) { ! 1140: b = IE_TxI | IE_LSI; ! 1141: if (rstty.rt_cflag & CREAD) ! 1142: b |= IE_RxI; ! 1143: } ! 1144: outb( PORT+IER, b ); ! 1145: ! 1146: /* ! 1147: * Enable interrupts. ! 1148: */ ! 1149: spl( s ); ! 1150: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.