|
|
1.1 ! root 1: /* ! 2: ! 3: Copyright 1990,1991,1992 Eric R. Smith. All rights reserved. ! 4: ! 5: */ ! 6: ! 7: ! 8: ! 9: /* ! 10: ! 11: * read/write routines for TTY devices ! 12: ! 13: */ ! 14: ! 15: ! 16: ! 17: #include "mint.h" ! 18: ! 19: ! 20: ! 21: static void _erase P_((FILEPTR *, int)); ! 22: ! 23: static int escseq P_((struct tty *, int)); ! 24: ! 25: ! 26: ! 27: /* setting a special character to this value disables it */ ! 28: ! 29: #define UNDEF 0 ! 30: ! 31: ! 32: ! 33: ! 34: ! 35: /* default terminal characteristics */ ! 36: ! 37: ! 38: ! 39: struct tty default_tty = { ! 40: ! 41: 0, /* process group */ ! 42: ! 43: 0, /* state */ ! 44: ! 45: 0, /* use_cnt */ ! 46: ! 47: 0, /* reserved short */ ! 48: ! 49: { ! 50: ! 51: 13, 13, /* input speed == output speed == 9600 baud */ ! 52: ! 53: CTRL('H'), /* erase */ ! 54: ! 55: CTRL('U'), /* kill */ ! 56: ! 57: T_ECHO|T_CRMOD|T_TOSTOP|T_XKEY, /* flags */ ! 58: ! 59: }, ! 60: ! 61: { ! 62: ! 63: CTRL('C'), /* interrupt */ ! 64: ! 65: CTRL('\\'), /* quit */ ! 66: ! 67: CTRL('Q'), /* start */ ! 68: ! 69: CTRL('S'), /* stop */ ! 70: ! 71: CTRL('D'), /* EOF */ ! 72: ! 73: '\r' /* alternate end of line */ ! 74: ! 75: }, ! 76: ! 77: { ! 78: ! 79: CTRL('Z'), /* suspend */ ! 80: ! 81: CTRL('Y'), /* suspend after read */ ! 82: ! 83: CTRL('R'), /* reprint */ ! 84: ! 85: UNDEF, /* flush output */ ! 86: ! 87: UNDEF, /* erase word */ ! 88: ! 89: UNDEF /* quote next char */ ! 90: ! 91: }, ! 92: ! 93: { ! 94: ! 95: 0, 0, 0, 0 /* window size is unknown */ ! 96: ! 97: }, ! 98: ! 99: 0, /* no process is selecting us for reading */ ! 100: ! 101: 0, /* or for writing */ ! 102: ! 103: 0 /* use default XKEY map */ ! 104: ! 105: }; ! 106: ! 107: ! 108: ! 109: #define _put(f, c) (tty_putchar((f), (c), RAW)) ! 110: ! 111: ! 112: ! 113: static void ! 114: ! 115: _erase(f, c) ! 116: ! 117: FILEPTR *f; ! 118: ! 119: int c; ! 120: ! 121: { ! 122: ! 123: _put(f, '\010'); ! 124: ! 125: _put(f, ' '); ! 126: ! 127: _put(f, '\010'); ! 128: ! 129: /* watch out for control characters -- they're printed as e.g. "^C" */ ! 130: ! 131: if (c >= 0 && c < ' ') { ! 132: ! 133: _put(f, '\010'); _put(f, ' '); _put(f, '\010'); ! 134: ! 135: } ! 136: ! 137: } ! 138: ! 139: ! 140: ! 141: #define put(f, c) { if (mode & T_ECHO) _put(f, c); } ! 142: ! 143: #define erase(f, c) { if (mode & T_ECHO) _erase(f, c); } ! 144: ! 145: ! 146: ! 147: long ! 148: ! 149: tty_read(f, buf, nbytes) ! 150: ! 151: FILEPTR *f; ! 152: ! 153: void *buf; ! 154: ! 155: long nbytes; ! 156: ! 157: { ! 158: ! 159: long r; ! 160: ! 161: long bytes_read = 0; ! 162: ! 163: unsigned char ch, *ptr; ! 164: ! 165: int rdmode, mode; ! 166: ! 167: struct tty *tty; ! 168: ! 169: ! 170: ! 171: tty = (struct tty *)f->devinfo; ! 172: ! 173: assert(tty != 0); ! 174: ! 175: ! 176: ! 177: if (f->flags & O_HEAD) { /* pty server side? */ ! 178: ! 179: rdmode = RAW; /* yes -- always raw mode */ ! 180: ! 181: mode = T_RAW; ! 182: ! 183: } ! 184: ! 185: else if (curproc->domain == DOM_MINT) { /* MiNT domain process? */ ! 186: ! 187: mode = tty->sg.sg_flags; ! 188: ! 189: rdmode = COOKED|NOECHO; ! 190: ! 191: if ( mode & (T_RAW | T_CBREAK) ) { ! 192: ! 193: rdmode = (mode & T_RAW) ? RAW : COOKED; ! 194: ! 195: } ! 196: ! 197: if (mode & T_XKEY) ! 198: ! 199: rdmode |= ESCSEQ; ! 200: ! 201: } ! 202: ! 203: else { ! 204: ! 205: rdmode = COOKED|NOECHO; ! 206: ! 207: mode = T_TOS | T_ECHO; ! 208: ! 209: } ! 210: ! 211: ! 212: ! 213: ptr = buf; ! 214: ! 215: ! 216: ! 217: while (bytes_read < nbytes) { ! 218: ! 219: r = tty_getchar(f, rdmode); ! 220: ! 221: if (r < 0) { ! 222: ! 223: DEBUG("tty_read: tty_getchar returned %ld", r); ! 224: ! 225: return (bytes_read) ? bytes_read : r; ! 226: ! 227: } ! 228: ! 229: else if (r == MiNTEOF) ! 230: ! 231: return bytes_read; ! 232: ! 233: ch = r & 0xff; ! 234: ! 235: ! 236: ! 237: if ( (mode & T_CRMOD) && (ch == '\r') ) ! 238: ! 239: ch = '\n'; ! 240: ! 241: ! 242: ! 243: /* 1 character reads in TOS mode are always raw */ ! 244: ! 245: if (nbytes == 1 && (mode & T_TOS)) { ! 246: ! 247: put(f, ch); ! 248: ! 249: *ptr = ch; ! 250: ! 251: return 1; ! 252: ! 253: } ! 254: ! 255: ! 256: ! 257: /* T_CBREAK mode doesn't do erase or kill processing */ ! 258: ! 259: /* also note that setting a special character to UNDEF disables it */ ! 260: ! 261: ! 262: ! 263: if (rdmode & COOKED && !(mode & T_CBREAK) && ch != UNDEF) { ! 264: ! 265: if ((char)ch == tty->sg.sg_erase) { /* backspace */ ! 266: ! 267: if (bytes_read > 0) { ! 268: ! 269: --ptr; ! 270: ! 271: erase(f, *ptr); ! 272: ! 273: bytes_read--; ! 274: ! 275: } ! 276: ! 277: continue; ! 278: ! 279: } ! 280: ! 281: else if (ch == CTRL('X')) { ! 282: ! 283: while (bytes_read > 0) { ! 284: ! 285: --ptr; ! 286: ! 287: erase(f, *ptr); ! 288: ! 289: bytes_read--; ! 290: ! 291: } ! 292: ! 293: continue; ! 294: ! 295: } ! 296: ! 297: else if ((char)ch ==tty->ltc.t_rprntc || ! 298: ! 299: (char)ch == tty->sg.sg_kill) { ! 300: ! 301: if (mode & T_TOS) ! 302: ! 303: put(f, '#'); ! 304: ! 305: put(f, '\r'); ! 306: ! 307: put(f, '\n'); ! 308: ! 309: ptr = buf; ! 310: ! 311: if ((char)ch == tty->sg.sg_kill) { ! 312: ! 313: bytes_read = 0; ! 314: ! 315: } ! 316: ! 317: else { ! 318: ! 319: for (r = 0; r < bytes_read; r++, ptr++) ! 320: ! 321: put(f, *ptr); ! 322: ! 323: } ! 324: ! 325: continue; ! 326: ! 327: } ! 328: ! 329: else if ((char)ch == tty->tc.t_eofc && !(mode & T_TOS)) ! 330: ! 331: return bytes_read; ! 332: ! 333: } ! 334: ! 335: ! 336: ! 337: /* both T_CBREAK and T_COOKED modes have to do signals, though */ ! 338: ! 339: if ((rdmode & COOKED) && ch != UNDEF) { ! 340: ! 341: if ((char)ch == tty->tc.t_intrc ! 342: ! 343: || (char)ch == tty->tc.t_quitc ! 344: ! 345: || (char)ch == tty->ltc.t_dsuspc ! 346: ! 347: || (char)ch == tty->ltc.t_suspc ! 348: ! 349: ) { ! 350: ! 351: /* the device driver raised the appropriate signal; if we get here, the ! 352: ! 353: signal was caught by the user (or ignored). flush buffers and continue ! 354: ! 355: */ ! 356: ! 357: if (!(tty->sg.sg_flags & T_NOFLSH)) { ! 358: ! 359: DEBUG("tty_read: flushing input"); ! 360: ! 361: bytes_read = 0; ! 362: ! 363: ptr = buf; ! 364: ! 365: } ! 366: ! 367: continue; ! 368: ! 369: } ! 370: ! 371: else if (ch == '\n' || (char)ch == tty->tc.t_brkc) { ! 372: ! 373: put(f, '\r'); ! 374: ! 375: if (!(mode & T_TOS)) { ! 376: ! 377: *ptr++ = ch; ! 378: ! 379: put(f, '\n'); ! 380: ! 381: bytes_read++; ! 382: ! 383: } ! 384: ! 385: return bytes_read; ! 386: ! 387: } ! 388: ! 389: ! 390: ! 391: } ! 392: ! 393: ! 394: ! 395: /* do the following for both RAW and COOKED mode */ ! 396: ! 397: *ptr++ = ch; ! 398: ! 399: if (ch < ' ') { /* ch is unsigned */ ! 400: ! 401: put(f, '^'); put(f, ch+'@'); ! 402: ! 403: } ! 404: ! 405: else ! 406: ! 407: put(f, ch); ! 408: ! 409: bytes_read++; ! 410: ! 411: ! 412: ! 413: /* for RAW mode, if there are no more characters then break */ ! 414: ! 415: if ( (mode & (T_RAW|T_CBREAK)) && ! 416: ! 417: !((rdmode & ESCSEQ) && (tty->state & TS_ESC))) { ! 418: ! 419: r = 1; ! 420: ! 421: (void)(*f->dev->ioctl)(f, FIONREAD, &r); ! 422: ! 423: if (r <= 0) break; ! 424: ! 425: } ! 426: ! 427: } ! 428: ! 429: ! 430: ! 431: return bytes_read; ! 432: ! 433: } ! 434: ! 435: ! 436: ! 437: long ! 438: ! 439: tty_write(f, buf, nbytes) ! 440: ! 441: FILEPTR *f; ! 442: ! 443: const void *buf; ! 444: ! 445: long nbytes; ! 446: ! 447: { ! 448: ! 449: unsigned const char *ptr; ! 450: ! 451: long c; ! 452: ! 453: long bytes_written; ! 454: ! 455: int mode, rwmode; ! 456: ! 457: struct tty *tty; ! 458: ! 459: int use_putchar = 0; ! 460: ! 461: static long cr_char = '\r'; ! 462: ! 463: #define LBUFSIZ 128 ! 464: ! 465: long lbuf[LBUFSIZ]; ! 466: ! 467: ! 468: ! 469: tty = (struct tty *)f->devinfo; ! 470: ! 471: assert(tty != 0); ! 472: ! 473: ! 474: ! 475: ptr = buf; ! 476: ! 477: if (f->flags & O_HEAD) { ! 478: ! 479: use_putchar = 1; ! 480: ! 481: mode = T_RAW; ! 482: ! 483: } ! 484: ! 485: else if (curproc->domain == DOM_TOS) ! 486: ! 487: /* for TOS programs, 1 byte writes are always in raw mode */ ! 488: ! 489: mode = (nbytes == 1) ? T_RAW : T_TOS; ! 490: ! 491: else ! 492: ! 493: mode = tty->sg.sg_flags; ! 494: ! 495: ! 496: ! 497: rwmode = (mode & T_RAW) ? RAW : COOKED; ! 498: ! 499: ! 500: ! 501: bytes_written = 0; ! 502: ! 503: ! 504: ! 505: /* ! 506: ! 507: * "mode" can now be reduced to just T_CRMODE or not ! 508: ! 509: */ ! 510: ! 511: if ((curproc->domain == DOM_MINT) && (mode & T_CRMOD) && ! 512: ! 513: !(mode & T_RAW)) ! 514: ! 515: mode = T_CRMOD; ! 516: ! 517: else ! 518: ! 519: mode = 0; ! 520: ! 521: ! 522: ! 523: /* ! 524: ! 525: * we always write at least 1 byte with tty_putchar, since that takes ! 526: ! 527: * care of job control and terminal states. After that, we may be able ! 528: ! 529: * to use (*f->dev->write) directly. ! 530: ! 531: */ ! 532: ! 533: ! 534: ! 535: ! 536: ! 537: if (nbytes == 0) return bytes_written; ! 538: ! 539: c = *ptr++; ! 540: ! 541: ! 542: ! 543: if (c == '\n' && mode) { /* remember, "mode" now means CRMOD */ ! 544: ! 545: tty_putchar(f, cr_char, rwmode); ! 546: ! 547: } ! 548: ! 549: tty_putchar(f, c, rwmode); ! 550: ! 551: nbytes--; ! 552: ! 553: bytes_written++; ! 554: ! 555: ! 556: ! 557: if (use_putchar) { ! 558: ! 559: while (nbytes-- > 0) { ! 560: ! 561: c = *ptr++; ! 562: ! 563: if (c == '\n' && mode) ! 564: ! 565: tty_putchar(f, cr_char, rwmode); ! 566: ! 567: tty_putchar(f, c, rwmode); ! 568: ! 569: bytes_written++; ! 570: ! 571: } ! 572: ! 573: } else { ! 574: ! 575: /* write in big chunks if possible; but never more than 1 line ! 576: ! 577: * (so that ^S/^Q can happen reasonably quickly for the user) ! 578: ! 579: */ ! 580: ! 581: long bytes_to_write = 0; ! 582: ! 583: long *s = lbuf; ! 584: ! 585: ! 586: ! 587: while (nbytes-- > 0) { ! 588: ! 589: c = *ptr++; ! 590: ! 591: if (c == '\n') { ! 592: ! 593: if (bytes_to_write) { ! 594: ! 595: (*f->dev->write)(f, (char *)lbuf, ! 596: ! 597: bytes_to_write); ! 598: ! 599: bytes_to_write = 0; ! 600: ! 601: s = lbuf; ! 602: ! 603: } ! 604: ! 605: if (mode) /* i.e. T_CRMODE */ ! 606: ! 607: tty_putchar(f, cr_char, rwmode); ! 608: ! 609: tty_putchar(f, (long)c, rwmode); ! 610: ! 611: bytes_written++; ! 612: ! 613: } else { ! 614: ! 615: *s++ = c; ! 616: ! 617: bytes_written++; ! 618: ! 619: bytes_to_write += 4; ! 620: ! 621: if (bytes_to_write >= LBUFSIZ*4) { ! 622: ! 623: (*f->dev->write)(f, (char *)lbuf, ! 624: ! 625: bytes_to_write); ! 626: ! 627: bytes_to_write = 0; ! 628: ! 629: s = lbuf; ! 630: ! 631: } ! 632: ! 633: } ! 634: ! 635: } ! 636: ! 637: if (bytes_to_write) { ! 638: ! 639: (*f->dev->write)(f, (char *)lbuf, bytes_to_write); ! 640: ! 641: } ! 642: ! 643: } ! 644: ! 645: ! 646: ! 647: return bytes_written; ! 648: ! 649: } ! 650: ! 651: ! 652: ! 653: /* some notable scan codes */ ! 654: ! 655: #define K_INSERT 0x52 ! 656: ! 657: #define K_HOME 0x47 ! 658: ! 659: #define K_UNDO 0x61 ! 660: ! 661: #define K_HELP 0x62 ! 662: ! 663: #define CURS_UP 0x48 ! 664: ! 665: #define CURS_DN 0x50 ! 666: ! 667: #define CURS_RT 0x4d ! 668: ! 669: #define CURS_LF 0x4b ! 670: ! 671: #define F_1 0x3b ! 672: ! 673: #define F_10 0x44 ! 674: ! 675: #define F_11 0x54 ! 676: ! 677: #define F_20 0x5d ! 678: ! 679: #define ALT_1 0x78 ! 680: ! 681: #define ALT_0 0x81 ! 682: ! 683: ! 684: ! 685: /* Default function key table: ! 686: ! 687: * entries: 0-9 are F1-F10 ! 688: ! 689: * 10-19 are F11-F20 ! 690: ! 691: * 20-23 are cursor up, down, right, and left ! 692: ! 693: * 24-27 are help, undo, insert, and home ! 694: ! 695: * 28-31 are shift+cursor up, down, right, and left ! 696: ! 697: */ ! 698: ! 699: ! 700: ! 701: static char vt52xkey[256] = { ! 702: ! 703: '\033', 'P', 0, 0, 0, 0, 0, 0, ! 704: ! 705: '\033', 'Q', 0, 0, 0, 0, 0, 0, ! 706: ! 707: '\033', 'R', 0, 0, 0, 0, 0, 0, ! 708: ! 709: '\033', 'S', 0, 0, 0, 0, 0, 0, ! 710: ! 711: '\033', 'T', 0, 0, 0, 0, 0, 0, ! 712: ! 713: '\033', 'U', 0, 0, 0, 0, 0, 0, ! 714: ! 715: '\033', 'V', 0, 0, 0, 0, 0, 0, ! 716: ! 717: '\033', 'W', 0, 0, 0, 0, 0, 0, ! 718: ! 719: '\033', 'X', 0, 0, 0, 0, 0, 0, ! 720: ! 721: '\033', 'Y', 0, 0, 0, 0, 0, 0, ! 722: ! 723: '\033', 'p', 0, 0, 0, 0, 0, 0, ! 724: ! 725: '\033', 'q', 0, 0, 0, 0, 0, 0, ! 726: ! 727: '\033', 'r', 0, 0, 0, 0, 0, 0, ! 728: ! 729: '\033', 's', 0, 0, 0, 0, 0, 0, ! 730: ! 731: '\033', 't', 0, 0, 0, 0, 0, 0, ! 732: ! 733: '\033', 'u', 0, 0, 0, 0, 0, 0, ! 734: ! 735: '\033', 'v', 0, 0, 0, 0, 0, 0, ! 736: ! 737: '\033', 'w', 0, 0, 0, 0, 0, 0, ! 738: ! 739: '\033', 'x', 0, 0, 0, 0, 0, 0, ! 740: ! 741: '\033', 'y', 0, 0, 0, 0, 0, 0, ! 742: ! 743: '\033', 'A', 0, 0, 0, 0, 0, 0, ! 744: ! 745: '\033', 'B', 0, 0, 0, 0, 0, 0, ! 746: ! 747: '\033', 'C', 0, 0, 0, 0, 0, 0, ! 748: ! 749: '\033', 'D', 0, 0, 0, 0, 0, 0, ! 750: ! 751: '\033', 'H', 0, 0, 0, 0, 0, 0, ! 752: ! 753: '\033', 'K', 0, 0, 0, 0, 0, 0, ! 754: ! 755: '\033', 'I', 0, 0, 0, 0, 0, 0, ! 756: ! 757: '\033', 'E', 0, 0, 0, 0, 0, 0, ! 758: ! 759: '\033', 'a', 0, 0, 0, 0, 0, 0, ! 760: ! 761: '\033', 'b', 0, 0, 0, 0, 0, 0, ! 762: ! 763: '\033', 'c', 0, 0, 0, 0, 0, 0, ! 764: ! 765: '\033', 'd', 0, 0, 0, 0, 0, 0, ! 766: ! 767: }; ! 768: ! 769: ! 770: ! 771: static char unxbaud P_((long)); ! 772: ! 773: ! 774: ! 775: /* convert a number describing the baud rate into a Unix ! 776: ! 777: * style baud rate number. Returns the Unix baud rate, ! 778: ! 779: * or 16 (EXTA) if the rate is unknown ! 780: ! 781: */ ! 782: ! 783: ! 784: ! 785: #define EXTA 16 ! 786: ! 787: ! 788: ! 789: static long ubaud[EXTA] = { ! 790: ! 791: 0L, 50L, 75L, 110L, 134L, 150L, 200L, 300L, ! 792: ! 793: 600L, 1200L, 1800L, 2400L, 4800L, 9600L, 19200L, 38400L ! 794: ! 795: }; ! 796: ! 797: ! 798: ! 799: static char ! 800: ! 801: unxbaud(baud) ! 802: ! 803: long baud; ! 804: ! 805: { ! 806: ! 807: int i; ! 808: ! 809: for (i = 1; i < EXTA; i++) { ! 810: ! 811: if (ubaud[i] == baud) ! 812: ! 813: break; ! 814: ! 815: } ! 816: ! 817: return i; ! 818: ! 819: } ! 820: ! 821: ! 822: ! 823: #define tosbaud(c) ( ((c) < 0 || (c) >= EXTA) ? -1L : ubaud[c] ) ! 824: ! 825: ! 826: ! 827: long ! 828: ! 829: tty_ioctl(f, mode, arg) ! 830: ! 831: FILEPTR *f; ! 832: ! 833: int mode; ! 834: ! 835: void *arg; ! 836: ! 837: { ! 838: ! 839: struct sgttyb *sg; ! 840: ! 841: struct tchars *tc; ! 842: ! 843: struct ltchars *ltc; ! 844: ! 845: struct tty *tty; ! 846: ! 847: struct winsize *sz; ! 848: ! 849: struct xkey *xk; ! 850: ! 851: char *xktab; ! 852: ! 853: int i; ! 854: ! 855: long baud; ! 856: ! 857: short flags; ! 858: ! 859: ! 860: ! 861: if (!is_terminal(f)) { ! 862: ! 863: DEBUG("tty_ioctl(mode %x): file is not a tty", mode); ! 864: ! 865: return EINVFN; ! 866: ! 867: } ! 868: ! 869: tty = (struct tty *)f->devinfo; ! 870: ! 871: assert(tty != 0); ! 872: ! 873: ! 874: ! 875: switch(mode) { ! 876: ! 877: case TIOCGETP: ! 878: ! 879: sg = (struct sgttyb *)arg; ! 880: ! 881: /* get input and output baud rates from the terminal device */ ! 882: ! 883: baud = -1L; ! 884: ! 885: (*f->dev->ioctl)(f, TIOCIBAUD, &baud); ! 886: ! 887: tty->sg.sg_ispeed = unxbaud(baud); ! 888: ! 889: baud = -1L; ! 890: ! 891: (*f->dev->ioctl)(f, TIOCOBAUD, &baud); ! 892: ! 893: tty->sg.sg_ospeed = unxbaud(baud); ! 894: ! 895: /* get terminal flags */ ! 896: ! 897: flags = 0; ! 898: ! 899: if ((*f->dev->ioctl)(f, TIOCGFLAGS, &flags) == 0) { ! 900: ! 901: tty->sg.sg_flags &= ~TF_FLAGS; ! 902: ! 903: tty->sg.sg_flags |= (flags & TF_FLAGS); ! 904: ! 905: } ! 906: ! 907: *sg = tty->sg; ! 908: ! 909: return 0; ! 910: ! 911: case TIOCSETP: ! 912: ! 913: sg = (struct sgttyb *)arg; ! 914: ! 915: tty->sg = *sg; ! 916: ! 917: /* set baud rates */ ! 918: ! 919: baud = tosbaud(sg->sg_ispeed); ! 920: ! 921: (*f->dev->ioctl)(f, TIOCIBAUD, &baud); ! 922: ! 923: baud = tosbaud(sg->sg_ospeed); ! 924: ! 925: (*f->dev->ioctl)(f, TIOCOBAUD, &baud); ! 926: ! 927: /* set parity, etc. */ ! 928: ! 929: flags = TF_8BIT; ! 930: ! 931: if (sg->sg_flags & (T_EVENP|T_ODDP)) { ! 932: ! 933: flags = TF_7BIT; ! 934: ! 935: } ! 936: ! 937: flags |= (sg->sg_flags & TF_FLAGS); ! 938: ! 939: (*f->dev->ioctl)(f, TIOCSFLAGS, &flags); ! 940: ! 941: return 0; ! 942: ! 943: case TIOCGETC: ! 944: ! 945: tc = (struct tchars *)arg; ! 946: ! 947: *tc = tty->tc; ! 948: ! 949: return 0; ! 950: ! 951: case TIOCSETC: ! 952: ! 953: tc = (struct tchars *)arg; ! 954: ! 955: tty->tc = *tc; ! 956: ! 957: return 0; ! 958: ! 959: case TIOCGLTC: ! 960: ! 961: ltc = (struct ltchars *)arg; ! 962: ! 963: *ltc = tty->ltc; ! 964: ! 965: return 0; ! 966: ! 967: case TIOCSLTC: ! 968: ! 969: ltc = (struct ltchars *)arg; ! 970: ! 971: tty->ltc = *ltc; ! 972: ! 973: return 0; ! 974: ! 975: case TIOCGWINSZ: ! 976: ! 977: sz = (struct winsize *)arg; ! 978: ! 979: *sz = tty->wsiz; ! 980: ! 981: return 0; ! 982: ! 983: case TIOCSWINSZ: ! 984: ! 985: sz = (struct winsize *)arg; ! 986: ! 987: tty->wsiz = *sz; ! 988: ! 989: return 0; ! 990: ! 991: case TIOCGPGRP: ! 992: ! 993: *((long *)arg) = tty->pgrp; ! 994: ! 995: return 0; ! 996: ! 997: case TIOCSPGRP: ! 998: ! 999: tty->pgrp = (*((long *)arg) & 0x00007fffL); ! 1000: ! 1001: return 0; ! 1002: ! 1003: case TIOCSTART: ! 1004: ! 1005: tty->state &= ~TS_HOLD; ! 1006: ! 1007: return 0; ! 1008: ! 1009: case TIOCSTOP: ! 1010: ! 1011: tty->state |= TS_HOLD; ! 1012: ! 1013: return 0; ! 1014: ! 1015: case TIOCGXKEY: ! 1016: ! 1017: xk = (struct xkey *)arg; ! 1018: ! 1019: i = xk->xk_num; ! 1020: ! 1021: if (i < 0 || i > 31) return ERANGE; ! 1022: ! 1023: xktab = tty->xkey; ! 1024: ! 1025: if (!xktab) xktab = vt52xkey; ! 1026: ! 1027: xktab += i*8; ! 1028: ! 1029: for (i = 0; i < 8; i++) ! 1030: ! 1031: xk->xk_def[i] = *xktab++; ! 1032: ! 1033: return 0; ! 1034: ! 1035: case TIOCSXKEY: ! 1036: ! 1037: xk = (struct xkey *)arg; ! 1038: ! 1039: xktab = tty->xkey; ! 1040: ! 1041: if (!xktab) { ! 1042: ! 1043: xktab = kmalloc((long)256); ! 1044: ! 1045: if (!xktab) return ENSMEM; ! 1046: ! 1047: for (i = 0; i < 256; i++) ! 1048: ! 1049: xktab[i] = vt52xkey[i]; ! 1050: ! 1051: tty->xkey = xktab; ! 1052: ! 1053: } ! 1054: ! 1055: i = xk->xk_num; ! 1056: ! 1057: if (i < 0 || i > 31) return ERANGE; ! 1058: ! 1059: xktab += i*8; ! 1060: ! 1061: for (i = 0; i < 7; i++) ! 1062: ! 1063: xktab[i] = xk->xk_def[i]; ! 1064: ! 1065: xktab[7] = 0; ! 1066: ! 1067: return 0; ! 1068: ! 1069: default: ! 1070: ! 1071: DEBUG("tty_ioctl: bad function call"); ! 1072: ! 1073: return EINVFN; ! 1074: ! 1075: } ! 1076: ! 1077: } ! 1078: ! 1079: ! 1080: ! 1081: /* ! 1082: ! 1083: * function for translating extended characters (e.g. cursor keys, or ! 1084: ! 1085: * ALT+key sequences) into either escape sequences or meta characters. ! 1086: ! 1087: * for escape sequences, we return the the first character of the ! 1088: ! 1089: * sequence (normally ESC) and set the tty's state so that subsequent ! 1090: ! 1091: * calls to tty_getchar will pick up the remaining characters. ! 1092: ! 1093: * Note that escape sequences are limited to 7 characters at most. ! 1094: ! 1095: */ ! 1096: ! 1097: ! 1098: ! 1099: static int ! 1100: ! 1101: escseq(tty, scan) ! 1102: ! 1103: struct tty *tty; ! 1104: ! 1105: int scan; ! 1106: ! 1107: { ! 1108: ! 1109: char *tab; ! 1110: ! 1111: int i; ! 1112: ! 1113: ! 1114: ! 1115: switch(scan) { ! 1116: ! 1117: case CURS_UP: i = 20; break; ! 1118: ! 1119: case CURS_DN: i = 21; break; ! 1120: ! 1121: case CURS_RT: i = 22; break; ! 1122: ! 1123: case CURS_LF: i = 23; break; ! 1124: ! 1125: case K_HELP: i = 24; break; ! 1126: ! 1127: case K_UNDO: i = 25; break; ! 1128: ! 1129: case K_INSERT:i = 26; break; ! 1130: ! 1131: case K_HOME: i = 27; break; ! 1132: ! 1133: case CURS_UP+0x100: i = 28; break; ! 1134: ! 1135: case CURS_DN+0x100: i = 29; break; ! 1136: ! 1137: case CURS_RT+0x100: i = 30; break; ! 1138: ! 1139: case CURS_LF+0x100: i = 31; break; ! 1140: ! 1141: default: ! 1142: ! 1143: if (scan >= F_1 && scan <= F_10) { ! 1144: ! 1145: i = scan - F_1; ! 1146: ! 1147: } else if (scan >= F_11 && scan <= F_20) { ! 1148: ! 1149: i = 10 + scan - F_11; ! 1150: ! 1151: } else ! 1152: ! 1153: i = -1; ! 1154: ! 1155: } ! 1156: ! 1157: ! 1158: ! 1159: if (i >= 0) { /* an extended escape sequence */ ! 1160: ! 1161: tab = tty->xkey; ! 1162: ! 1163: if (!tab) tab = vt52xkey; ! 1164: ! 1165: i *= 8; ! 1166: ! 1167: scan = tab[i++]; ! 1168: ! 1169: if (scan) { ! 1170: ! 1171: if (tab[i] == 0) i = 0; ! 1172: ! 1173: tty->state = (tty->state & ~TS_ESC) | i; ! 1174: ! 1175: } ! 1176: ! 1177: return scan; ! 1178: ! 1179: } ! 1180: ! 1181: ! 1182: ! 1183: if (scan >= ALT_1 && scan <= ALT_0) { ! 1184: ! 1185: scan -= (ALT_1-1); ! 1186: ! 1187: if (scan == 10) scan = 0; ! 1188: ! 1189: return (scan + '0') | 0x80; ! 1190: ! 1191: } ! 1192: ! 1193: ! 1194: ! 1195: tab = *( ((char **)Keytbl((void *)-1L, (void *)-1L, (void *)-1L)) + 2 ); /* gratuitous (void *) for Lattice */ ! 1196: ! 1197: scan = tab[scan]; ! 1198: ! 1199: if (scan >= 'A' && scan <= 'Z') return scan | 0x80; ! 1200: ! 1201: return 0; ! 1202: ! 1203: } ! 1204: ! 1205: ! 1206: ! 1207: long ! 1208: ! 1209: tty_getchar(f, mode) ! 1210: ! 1211: FILEPTR *f; ! 1212: ! 1213: int mode; ! 1214: ! 1215: { ! 1216: ! 1217: struct tty *tty = (struct tty *)f->devinfo; ! 1218: ! 1219: char c, *tab; ! 1220: ! 1221: long r, ret; ! 1222: ! 1223: int scan; ! 1224: ! 1225: int master = f->flags & O_HEAD; ! 1226: ! 1227: ! 1228: ! 1229: assert(tty); ! 1230: ! 1231: ! 1232: ! 1233: /* pty masters never worry about job control and always read in raw mode */ ! 1234: ! 1235: if (master) { ! 1236: ! 1237: ret = (*f->dev->read)(f, (char *)&r, 4L); ! 1238: ! 1239: return (ret != 4L) ? MiNTEOF : r; ! 1240: ! 1241: } ! 1242: ! 1243: ! 1244: ! 1245: /* job control check */ ! 1246: ! 1247: if (tty->pgrp != curproc->pgrp && tty->pgrp > 0) { ! 1248: ! 1249: TRACE("job control: tty pgrp is %d proc pgrp is %d", ! 1250: ! 1251: tty->pgrp, curproc->pgrp); ! 1252: ! 1253: killgroup(curproc->pgrp, SIGTTIN); ! 1254: ! 1255: } ! 1256: ! 1257: ! 1258: ! 1259: if (mode & COOKED) ! 1260: ! 1261: tty->state |= TS_COOKED; ! 1262: ! 1263: else ! 1264: ! 1265: tty->state &= ~TS_COOKED; ! 1266: ! 1267: ! 1268: ! 1269: c = UNDEF+1; /* set to UNDEF when we successfully read a character */ ! 1270: ! 1271: ! 1272: ! 1273: /* we may be in the middle of an escape sequence */ ! 1274: ! 1275: if (scan = (tty->state & TS_ESC)) { ! 1276: ! 1277: if (mode & ESCSEQ) { ! 1278: ! 1279: tab = tty->xkey ? tty->xkey : vt52xkey; ! 1280: ! 1281: r = (unsigned char) tab[scan++]; ! 1282: ! 1283: if (r) { ! 1284: ! 1285: c = UNDEF; ! 1286: ! 1287: if (tab[scan] == 0) scan = 0; ! 1288: ! 1289: } ! 1290: ! 1291: else ! 1292: ! 1293: scan = 0; ! 1294: ! 1295: tty->state = (tty->state & ~TS_ESC) | scan; ! 1296: ! 1297: } ! 1298: ! 1299: else ! 1300: ! 1301: tty->state &= ~TS_ESC; ! 1302: ! 1303: } ! 1304: ! 1305: ! 1306: ! 1307: while (c != UNDEF) { ! 1308: ! 1309: ret = (*f->dev->read)(f, (char *)&r, 4L); ! 1310: ! 1311: if (ret != 4L) { ! 1312: ! 1313: DEBUG("EOF on tty device"); ! 1314: ! 1315: return MiNTEOF; ! 1316: ! 1317: } ! 1318: ! 1319: c = r & 0x00ff; ! 1320: ! 1321: scan = (r & 0x00ff0000) >> 16; ! 1322: ! 1323: if ( (c == 0) && (mode & ESCSEQ) && scan) { ! 1324: ! 1325: c = UNDEF; ! 1326: ! 1327: /* translate cursor keys, etc. into escape sequences or ! 1328: ! 1329: * META characters ! 1330: ! 1331: */ ! 1332: ! 1333: r = escseq(tty, scan); ! 1334: ! 1335: } else if ((mode & ESCSEQ) && ((scan == CURS_UP && c == '8') || ! 1336: ! 1337: (scan == CURS_DN && c == '2') || ! 1338: ! 1339: (scan == CURS_RT && c == '6') || ! 1340: ! 1341: (scan == CURS_LF && c == '4'))) { ! 1342: ! 1343: c = UNDEF; ! 1344: ! 1345: r = escseq(tty, scan+0x100); ! 1346: ! 1347: } else if (mode & COOKED) { ! 1348: ! 1349: if (c == UNDEF) ! 1350: ! 1351: ; /* do nothing */ ! 1352: ! 1353: else if (c == tty->ltc.t_dsuspc) ! 1354: ! 1355: killgroup(curproc->pgrp, SIGTSTP); ! 1356: ! 1357: else if (c == tty->tc.t_intrc) ! 1358: ! 1359: killgroup(curproc->pgrp, SIGINT); ! 1360: ! 1361: else if (c == tty->tc.t_stopc) ! 1362: ! 1363: tty->state |= TS_HOLD; ! 1364: ! 1365: else if (c == tty->tc.t_stopc) ! 1366: ! 1367: tty->state &= ~TS_HOLD; ! 1368: ! 1369: else ! 1370: ! 1371: c = UNDEF; ! 1372: ! 1373: } ! 1374: ! 1375: else ! 1376: ! 1377: c = UNDEF; ! 1378: ! 1379: } ! 1380: ! 1381: ! 1382: ! 1383: if (mode & ECHO) ! 1384: ! 1385: tty_putchar(f, r, mode); ! 1386: ! 1387: ! 1388: ! 1389: return r; ! 1390: ! 1391: } ! 1392: ! 1393: ! 1394: ! 1395: /* ! 1396: ! 1397: * tty_putchar: returns number of bytes successfully written ! 1398: ! 1399: */ ! 1400: ! 1401: ! 1402: ! 1403: long ! 1404: ! 1405: tty_putchar(f, data, mode) ! 1406: ! 1407: FILEPTR *f; ! 1408: ! 1409: long data; ! 1410: ! 1411: int mode; ! 1412: ! 1413: { ! 1414: ! 1415: struct tty *tty; ! 1416: ! 1417: int master; /* file is pty master side */ ! 1418: ! 1419: char ch; ! 1420: ! 1421: ! 1422: ! 1423: tty = (struct tty *)f->devinfo; ! 1424: ! 1425: ! 1426: ! 1427: master = f->flags & O_HEAD; ! 1428: ! 1429: ! 1430: ! 1431: /* pty masters don't need to worry about job control */ ! 1432: ! 1433: if (master) { ! 1434: ! 1435: ch = data & 0xff; ! 1436: ! 1437: ! 1438: ! 1439: if ( (tty->state & TS_COOKED) && ch != UNDEF) { ! 1440: ! 1441: /* see if we're putting control characters into the buffer */ ! 1442: ! 1443: if (ch == tty->tc.t_intrc) { ! 1444: ! 1445: tty->state &= ~TS_HOLD; ! 1446: ! 1447: killgroup(tty->pgrp, SIGINT); ! 1448: ! 1449: return 4L; ! 1450: ! 1451: } ! 1452: ! 1453: else if (ch == tty->tc.t_quitc) { ! 1454: ! 1455: tty->state &= ~TS_HOLD; ! 1456: ! 1457: killgroup(tty->pgrp, SIGQUIT); ! 1458: ! 1459: return 4L; ! 1460: ! 1461: } ! 1462: ! 1463: else if (ch == tty->ltc.t_suspc) { ! 1464: ! 1465: tty->state &= ~TS_HOLD; ! 1466: ! 1467: killgroup(tty->pgrp, SIGTSTP); ! 1468: ! 1469: return 4L; ! 1470: ! 1471: } ! 1472: ! 1473: else if (ch == tty->tc.t_stopc) { ! 1474: ! 1475: tty->state |= TS_HOLD; ! 1476: ! 1477: return 4L; ! 1478: ! 1479: } ! 1480: ! 1481: else if (ch == tty->tc.t_startc) { ! 1482: ! 1483: tty->state &= ~TS_HOLD; ! 1484: ! 1485: return 4L; ! 1486: ! 1487: } ! 1488: ! 1489: else if (tty->state & TS_HOLD) { ! 1490: ! 1491: return 0; ! 1492: ! 1493: } ! 1494: ! 1495: } ! 1496: ! 1497: goto do_putchar; ! 1498: ! 1499: } ! 1500: ! 1501: /* job control checks */ ! 1502: ! 1503: /* AKP: added T_TOSTOP; don't stop BG output if T_TOSTOP is clear */ ! 1504: ! 1505: if (tty->pgrp != curproc->pgrp && tty->pgrp > 0 ! 1506: ! 1507: && (tty->sg.sg_flags & T_TOSTOP)) { ! 1508: ! 1509: TRACE("job control: tty pgrp is %d proc pgrp is %d", ! 1510: ! 1511: tty->pgrp, curproc->pgrp); ! 1512: ! 1513: killgroup(curproc->pgrp, SIGTTOU); ! 1514: ! 1515: } ! 1516: ! 1517: ! 1518: ! 1519: if (mode & COOKED) { ! 1520: ! 1521: tty->state |= TS_COOKED; ! 1522: ! 1523: while (tty->state & TS_HOLD) ! 1524: ! 1525: nap(60); /* sleep for 60 milliseconds */ ! 1526: ! 1527: } ! 1528: ! 1529: else ! 1530: ! 1531: tty->state &= ~TS_COOKED; ! 1532: ! 1533: ! 1534: ! 1535: do_putchar: ! 1536: ! 1537: return (*f->dev->write)(f, (char *)&data, 4L); ! 1538: ! 1539: } ! 1540:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.