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