1: # 2: /* 3: */ 4: 5: /* 6: * general TTY subroutines 7: */ 8: #include "../param.h" 9: #include "../systm.h" 10: #include "../user.h" 11: #include "../tty.h" 12: #include "../proc.h" 13: #include "../inode.h" 14: #include "../file.h" 15: #include "../reg.h" 16: #include "../conf.h" 17: 18: /* 19: * Input mapping table-- if an entry is non-zero, when the 20: * corresponding character is typed preceded by "\" the escape 21: * sequence is replaced by the table value. Mostly used for 22: * upper-case only terminals. 23: */ 24: char maptab[] 25: { 26: 000,000,000,000,004,000,000,000, 27: 000,000,000,000,000,000,000,000, 28: 000,000,000,000,000,000,000,000, 29: 000,000,000,000,000,000,000,000, 30: 000,'|',000,'#',000,000,000,'`', 31: '{','}',000,000,000,000,000,000, 32: 000,000,000,000,000,000,000,000, 33: 000,000,000,000,000,000,000,000, 34: '@',000,000,000,000,000,000,000, 35: 000,000,000,000,000,000,000,000, 36: 000,000,000,000,000,000,000,000, 37: 000,000,000,000,000,000,'~',000, 38: 000,'A','B','C','D','E','F','G', 39: 'H','I','J','K','L','M','N','O', 40: 'P','Q','R','S','T','U','V','W', 41: 'X','Y','Z',000,000,000,000,000, 42: }; 43: 44: /* 45: * The actual structure of a clist block manipulated by 46: * getc and putc (mch.s) 47: */ 48: struct cblock { 49: struct cblock *c_next; 50: char info[6]; 51: }; 52: 53: /* The character lists-- space for 6*NCLIST characters */ 54: struct cblock cfree[NCLIST]; 55: /* List head for unused character blocks. */ 56: struct cblock *cfreelist; 57: 58: /* 59: * structure of device registers for KL, DL, and DC 60: * interfaces-- more particularly, those for which the 61: * SSTART bit is off and can be treated by general routines 62: * (that is, not DH). 63: */ 64: struct { 65: int ttrcsr; 66: int ttrbuf; 67: int tttcsr; 68: int tttbuf; 69: }; 70: 71: /* 72: * The routine implementing the gtty system call. 73: * Just call lower level routine and pass back values. 74: */ 75: gtty() 76: { 77: int v[3]; 78: register *up, *vp; 79: 80: vp = v; 81: sgtty(vp); 82: if (u.u_error) 83: return; 84: up = u.u_arg[0]; 85: suword(up, *vp++); 86: suword(++up, *vp++); 87: suword(++up, *vp++); 88: } 89: 90: /* 91: * The routine implementing the stty system call. 92: * Read in values and call lower level. 93: */ 94: stty() 95: { 96: register int *up; 97: 98: up = u.u_arg[0]; 99: u.u_arg[0] = fuword(up); 100: u.u_arg[1] = fuword(++up); 101: u.u_arg[2] = fuword(++up); 102: sgtty(0); 103: } 104: 105: /* 106: * Stuff common to stty and gtty. 107: * Check legality and switch out to individual 108: * device routine. 109: * v is 0 for stty; the parameters are taken from u.u_arg[]. 110: * c is non-zero for gtty and is the place in which the device 111: * routines place their information. 112: */ 113: sgtty(v) 114: int *v; 115: { 116: register struct file *fp; 117: register struct inode *ip; 118: 119: if ((fp = getf(u.u_ar0[R0])) == NULL) 120: return; 121: ip = fp->f_inode; 122: if ((ip->i_mode&IFMT) != IFCHR) { 123: u.u_error = ENOTTY; 124: return; 125: } 126: (*cdevsw[ip->i_addr[0].d_major].d_sgtty)(ip->i_addr[0], v); 127: } 128: 129: /* 130: * Wait for output to drain, then flush input waiting. 131: */ 132: wflushtty(atp) 133: struct tty *atp; 134: { 135: register struct tty *tp; 136: 137: tp = atp; 138: spl5(); 139: while (tp->t_outq.c_cc) { 140: tp->t_state =| ASLEEP; 141: sleep(&tp->t_outq, TTOPRI); 142: } 143: flushtty(tp); 144: spl0(); 145: } 146: 147: /* 148: * Initialize clist by freeing all character blocks, then count 149: * number of character devices. (Once-only routine) 150: */ 151: cinit() 152: { 153: register int ccp; 154: register struct cblock *cp; 155: register struct cdevsw *cdp; 156: 157: ccp = cfree; 158: for (cp=(ccp+07)&~07; cp <= &cfree[NCLIST-1]; cp++) { 159: cp->c_next = cfreelist; 160: cfreelist = cp; 161: } 162: ccp = 0; 163: for(cdp = cdevsw; cdp->d_open; cdp++) 164: ccp++; 165: nchrdev = ccp; 166: } 167: 168: /* 169: * flush all TTY queues 170: */ 171: flushtty(atp) 172: struct tty *atp; 173: { 174: register struct tty *tp; 175: register int sps; 176: 177: tp = atp; 178: while (getc(&tp->t_canq) >= 0); 179: while (getc(&tp->t_outq) >= 0); 180: wakeup(&tp->t_rawq); 181: wakeup(&tp->t_outq); 182: sps = PS->integ; 183: spl5(); 184: while (getc(&tp->t_rawq) >= 0); 185: tp->t_delct = 0; 186: PS->integ = sps; 187: } 188: 189: /* 190: * transfer raw input list to canonical list, 191: * doing erase-kill processing and handling escapes. 192: * It waits until a full line has been typed in cooked mode, 193: * or until any character has been typed in raw mode. 194: */ 195: canon(atp) 196: struct tty *atp; 197: { 198: register char *bp; 199: char *bp1; 200: register struct tty *tp; 201: register int c; 202: 203: tp = atp; 204: spl5(); 205: while (tp->t_delct==0) { 206: if ((tp->t_state&CARR_ON)==0) 207: return(0); 208: sleep(&tp->t_rawq, TTIPRI); 209: } 210: spl0(); 211: loop: 212: bp = &canonb[2]; 213: while ((c=getc(&tp->t_rawq)) >= 0) { 214: if (c==0377) { 215: tp->t_delct--; 216: break; 217: } 218: if ((tp->t_flags&RAW)==0) { 219: if (bp[-1]!='\\') { 220: if (c==tp->t_erase) { 221: if (bp > &canonb[2]) 222: bp--; 223: continue; 224: } 225: if (c==tp->t_kill) 226: goto loop; 227: if (c==CEOT) 228: continue; 229: } else 230: if (maptab[c] && (maptab[c]==c || (tp->t_flags&LCASE))) { 231: if (bp[-2] != '\\') 232: c = maptab[c]; 233: bp--; 234: } 235: } 236: *bp++ = c; 237: if (bp>=canonb+CANBSIZ) 238: break; 239: } 240: bp1 = bp; 241: bp = &canonb[2]; 242: c = &tp->t_canq; 243: while (bp<bp1) 244: putc(*bp++, c); 245: return(1); 246: } 247: 248: /* 249: * Place a character on raw TTY input queue, putting in delimiters 250: * and waking up top half as needed. 251: * Also echo if required. 252: * The arguments are the character and the appropriate 253: * tty structure. 254: */ 255: ttyinput(ac, atp) 256: struct tty *atp; 257: { 258: register int t_flags, c; 259: register struct tty *tp; 260: 261: tp = atp; 262: c = ac; 263: t_flags = tp->t_flags; 264: if ((c =& 0177) == '\r' && t_flags&CRMOD) 265: c = '\n'; 266: if ((t_flags&RAW)==0 && (c==CQUIT || c==CINTR)) { 267: signal(tp, c==CINTR? SIGINT:SIGQIT); 268: flushtty(tp); 269: return; 270: } 271: if (tp->t_rawq.c_cc>=TTYHOG) { 272: flushtty(tp); 273: return; 274: } 275: if (t_flags&LCASE && c>='A' && c<='Z') 276: c =+ 'a'-'A'; 277: putc(c, &tp->t_rawq); 278: if (t_flags&RAW || c=='\n' || c==004) { 279: wakeup(&tp->t_rawq); 280: if (putc(0377, &tp->t_rawq)==0) 281: tp->t_delct++; 282: } 283: if (t_flags&ECHO) { 284: ttyoutput(c, tp); 285: ttstart(tp); 286: } 287: } 288: 289: /* 290: * put character on TTY output queue, adding delays, 291: * expanding tabs, and handling the CR/NL bit. 292: * It is called both from the top half for output, and from 293: * interrupt level for echoing. 294: * The arguments are the character and the tty structure. 295: */ 296: ttyoutput(ac, tp) 297: struct tty *tp; 298: { 299: register int c; 300: register struct tty *rtp; 301: register char *colp; 302: int ctype; 303: 304: rtp = tp; 305: c = ac&0177; 306: /* 307: * Ignore EOT in normal mode to avoid hanging up 308: * certain terminals. 309: */ 310: if (c==004 && (rtp->t_flags&RAW)==0) 311: return; 312: /* 313: * Turn tabs to spaces as required 314: */ 315: if (c=='\t' && rtp->t_flags&XTABS) { 316: do 317: ttyoutput(' ', rtp); 318: while (rtp->t_col&07); 319: return; 320: } 321: /* 322: * for upper-case-only terminals, 323: * generate escapes. 324: */ 325: if (rtp->t_flags&LCASE) { 326: colp = "({)}!|^~'`"; 327: while(*colp++) 328: if(c == *colp++) { 329: ttyoutput('\\', rtp); 330: c = colp[-2]; 331: break; 332: } 333: if ('a'<=c && c<='z') 334: c =+ 'A' - 'a'; 335: } 336: /* 337: * turn <nl> to <cr><lf> if desired. 338: */ 339: if (c=='\n' && rtp->t_flags&CRMOD) 340: ttyoutput('\r', rtp); 341: if (putc(c, &rtp->t_outq)) 342: return; 343: /* 344: * Calculate delays. 345: * The numbers here represent clock ticks 346: * and are not necessarily optimal for all terminals. 347: * The delays are indicated by characters above 0200, 348: * thus (unfortunately) restricting the transmission 349: * path to 7 bits. 350: */ 351: colp = &rtp->t_col; 352: ctype = partab[c]; 353: c = 0; 354: switch (ctype&077) { 355: 356: /* ordinary */ 357: case 0: 358: (*colp)++; 359: 360: /* non-printing */ 361: case 1: 362: break; 363: 364: /* backspace */ 365: case 2: 366: if (*colp) 367: (*colp)--; 368: break; 369: 370: /* newline */ 371: case 3: 372: ctype = (rtp->t_flags >> 8) & 03; 373: if(ctype == 1) { /* tty 37 */ 374: if (*colp) 375: c = max((*colp>>4) + 3, 6); 376: } else 377: if(ctype == 2) { /* vt05 */ 378: c = 6; 379: } 380: *colp = 0; 381: break; 382: 383: /* tab */ 384: case 4: 385: ctype = (rtp->t_flags >> 10) & 03; 386: if(ctype == 1) { /* tty 37 */ 387: c = 1 - (*colp | ~07); 388: if(c < 5) 389: c = 0; 390: } 391: *colp =| 07; 392: (*colp)++; 393: break; 394: 395: /* vertical motion */ 396: case 5: 397: if(rtp->t_flags & VTDELAY) /* tty 37 */ 398: c = 0177; 399: break; 400: 401: /* carriage return */ 402: case 6: 403: ctype = (rtp->t_flags >> 12) & 03; 404: if(ctype == 1) { /* tn 300 */ 405: c = 5; 406: } else 407: if(ctype == 2) { /* ti 700 */ 408: c = 10; 409: } 410: *colp = 0; 411: } 412: if(c) 413: putc(c|0200, &rtp->t_outq); 414: } 415: 416: /* 417: * Restart typewriter output following a delay 418: * timeout. 419: * The name of the routine is passed to the timeout 420: * subroutine and it is called during a clock interrupt. 421: */ 422: ttrstrt(atp) 423: { 424: register struct tty *tp; 425: 426: tp = atp; 427: tp->t_state =& ~TIMEOUT; 428: ttstart(tp); 429: } 430: 431: /* 432: * Start output on the typewriter. It is used from the top half 433: * after some characters have been put on the output queue, 434: * from the interrupt routine to transmit the next 435: * character, and after a timeout has finished. 436: * If the SSTART bit is off for the tty the work is done here, 437: * using the protocol of the single-line interfaces (KL, DL, DC); 438: * otherwise the address word of the tty structure is 439: * taken to be the name of the device-dependent startup routine. 440: */ 441: ttstart(atp) 442: struct tty *atp; 443: { 444: register int *addr, c; 445: register struct tty *tp; 446: struct { int (*func)(); }; 447: 448: tp = atp; 449: addr = tp->t_addr; 450: if (tp->t_state&SSTART) { 451: (*addr.func)(tp); 452: return; 453: } 454: if ((addr->tttcsr&DONE)==0 || tp->t_state&TIMEOUT) 455: return; 456: if ((c=getc(&tp->t_outq)) >= 0) { 457: if (c<=0177) 458: addr->tttbuf = c | (partab[c]&0200); 459: else { 460: timeout(ttrstrt, tp, c&0177); 461: tp->t_state =| TIMEOUT; 462: } 463: } 464: } 465: 466: /* 467: * Called from device's read routine after it has 468: * calculated the tty-structure given as argument. 469: * The pc is backed up for the duration of this call. 470: * In case of a caught interrupt, an RTI will re-execute. 471: */ 472: ttread(atp) 473: struct tty *atp; 474: { 475: register struct tty *tp; 476: 477: tp = atp; 478: if ((tp->t_state&CARR_ON)==0) 479: return; 480: if (tp->t_canq.c_cc || canon(tp)) 481: while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0); 482: } 483: 484: /* 485: * Called from the device's write routine after it has 486: * calculated the tty-structure given as argument. 487: */ 488: ttwrite(atp) 489: struct tty *atp; 490: { 491: register struct tty *tp; 492: register int c; 493: 494: tp = atp; 495: if ((tp->t_state&CARR_ON)==0) 496: return; 497: while ((c=cpass())>=0) { 498: spl5(); 499: while (tp->t_outq.c_cc > TTHIWAT) { 500: ttstart(tp); 501: tp->t_state =| ASLEEP; 502: sleep(&tp->t_outq, TTOPRI); 503: } 504: spl0(); 505: ttyoutput(c, tp); 506: } 507: ttstart(tp); 508: } 509: 510: /* 511: * Common code for gtty and stty functions on typewriters. 512: * If v is non-zero then gtty is being done and information is 513: * passed back therein; 514: * if it is zero stty is being done and the input information is in the 515: * u_arg array. 516: */ 517: ttystty(atp, av) 518: int *atp, *av; 519: { 520: register *tp, *v; 521: 522: tp = atp; 523: if(v = av) { 524: *v++ = tp->t_speeds; 525: v->lobyte = tp->t_erase; 526: v->hibyte = tp->t_kill; 527: v[1] = tp->t_flags; 528: return(1); 529: } 530: wflushtty(tp); 531: v = u.u_arg; 532: tp->t_speeds = *v++; 533: tp->t_erase = v->lobyte; 534: tp->t_kill = v->hibyte; 535: tp->t_flags = v[1]; 536: return(0); 537: }