1 /* tty.c 4.22 82/03/15 */ 2 3 /* 4 * TTY subroutines common to more than one line discipline 5 */ 6 #include "../h/param.h" 7 #include "../h/systm.h" 8 #include "../h/dir.h" 9 #include "../h/user.h" 10 #include "../h/tty.h" 11 #include "../h/proc.h" 12 #include "../h/inode.h" 13 #include "../h/file.h" 14 #include "../h/reg.h" 15 #include "../h/conf.h" 16 #include "../h/buf.h" 17 #include "../h/dk.h" 18 19 char partab[]; 20 21 /* 22 * Input mapping table-- if an entry is non-zero, when the 23 * corresponding character is typed preceded by "\" the escape 24 * sequence is replaced by the table value. Mostly used for 25 * upper-case only terminals. 26 */ 27 28 char maptab[] ={ 29 000,000,000,000,000,000,000,000, 30 000,000,000,000,000,000,000,000, 31 000,000,000,000,000,000,000,000, 32 000,000,000,000,000,000,000,000, 33 000,'|',000,000,000,000,000,'`', 34 '{','}',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,000, 38 000,000,000,000,000,000,000,000, 39 000,000,000,000,000,000,000,000, 40 000,000,000,000,000,000,'~',000, 41 000,'A','B','C','D','E','F','G', 42 'H','I','J','K','L','M','N','O', 43 'P','Q','R','S','T','U','V','W', 44 'X','Y','Z',000,000,000,000,000, 45 }; 46 47 short tthiwat[16] = 48 { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; 49 short ttlowat[16] = 50 { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 51 52 #define OBUFSIZ 100 53 54 /* 55 * set default control characters. 56 */ 57 ttychars(tp) 58 register struct tty *tp; 59 { 60 61 tun.t_intrc = CINTR; 62 tun.t_quitc = CQUIT; 63 tun.t_startc = CSTART; 64 tun.t_stopc = CSTOP; 65 tun.t_eofc = CEOT; 66 tun.t_brkc = CBRK; 67 tp->t_erase = CERASE; 68 tp->t_kill = CKILL; 69 /* begin local */ 70 tlun.t_suspc = CTRL(z); 71 tlun.t_dsuspc = CTRL(y); 72 tlun.t_rprntc = CTRL(r); 73 tlun.t_flushc = CTRL(o); 74 tlun.t_werasc = CTRL(w); 75 tlun.t_lnextc = CTRL(v); 76 tp->t_local = 0; 77 tp->t_lstate = 0; 78 /* end local */ 79 } 80 81 /* 82 * Wait for output to drain, then flush input waiting. 83 */ 84 wflushtty(tp) 85 register struct tty *tp; 86 { 87 88 (void) spl5(); 89 while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 90 && tp->t_oproc) { /* kludge for pty */ 91 (*tp->t_oproc)(tp); 92 tp->t_state |= TS_ASLEEP; 93 sleep((caddr_t)&tp->t_outq, TTOPRI); 94 } 95 flushtty(tp, FREAD); 96 (void) spl0(); 97 } 98 99 /* 100 * flush all TTY queues 101 */ 102 flushtty(tp, rw) 103 register struct tty *tp; 104 { 105 register s; 106 107 s = spl6(); 108 if (rw & FREAD) { 109 while (getc(&tp->t_canq) >= 0) 110 ; 111 wakeup((caddr_t)&tp->t_rawq); 112 } 113 if (rw & FWRITE) { 114 wakeup((caddr_t)&tp->t_outq); 115 tp->t_state &= ~TS_TTSTOP; 116 (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 117 while (getc(&tp->t_outq) >= 0) 118 ; 119 } 120 if (rw & FREAD) { 121 while (getc(&tp->t_rawq) >= 0) 122 ; 123 tp->t_delct = 0; 124 tp->t_rocount = 0; /* local */ 125 tp->t_rocol = 0; 126 tp->t_lstate = 0; 127 } 128 splx(s); 129 } 130 131 /* 132 * Send stop character on input overflow. 133 */ 134 ttyblock(tp) 135 register struct tty *tp; 136 { 137 register x; 138 x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 139 if (tp->t_rawq.c_cc > TTYHOG) { 140 flushtty(tp, FREAD|FWRITE); 141 tp->t_state &= ~TS_TBLOCK; 142 } 143 if (x >= TTYHOG/2) { 144 if (putc(tun.t_stopc, &tp->t_outq)==0) { 145 tp->t_state |= TS_TBLOCK; 146 tp->t_char++; 147 ttstart(tp); 148 } 149 } 150 } 151 152 /* 153 * Restart typewriter output following a delay 154 * timeout. 155 * The name of the routine is passed to the timeout 156 * subroutine and it is called during a clock interrupt. 157 */ 158 ttrstrt(tp) 159 register struct tty *tp; 160 { 161 162 if (tp == 0) { 163 printf("ttrstrt: arg was 0!\n"); 164 return; 165 } 166 tp->t_state &= ~TS_TIMEOUT; 167 ttstart(tp); 168 } 169 170 /* 171 * Start output on the typewriter. It is used from the top half 172 * after some characters have been put on the output queue, 173 * from the interrupt routine to transmit the next 174 * character, and after a timeout has finished. 175 */ 176 ttstart(tp) 177 register struct tty *tp; 178 { 179 register s; 180 181 s = spl5(); 182 if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 183 tp->t_oproc) /* kludge for pty */ 184 (*tp->t_oproc)(tp); 185 splx(s); 186 } 187 188 /* 189 * Common code for tty ioctls. 190 */ 191 /*ARGSUSED*/ 192 ttioctl(tp, com, addr, flag) 193 register struct tty *tp; 194 caddr_t addr; 195 { 196 int dev; 197 unsigned t; 198 struct sgttyb iocb; 199 struct clist tq; 200 extern int nldisp; 201 register c; 202 int temp; 203 204 /* 205 * This is especially so that isatty() will 206 * fail when carrier is gone. 207 */ 208 if ((tp->t_state&TS_CARR_ON) == 0) { 209 u.u_error = EBADF; 210 return (1); 211 } 212 213 dev = tp->t_dev; 214 /* 215 * If the ioctl involves modification, 216 * insist on being able to write the device, 217 * and hang if in the background. 218 */ 219 switch(com) { 220 221 case TIOCSETD: 222 case TIOCSETP: 223 case TIOCSETN: 224 case TIOCFLUSH: 225 case TIOCSETC: 226 case TIOCSLTC: 227 case TIOCSPGRP: 228 case TIOCLBIS: 229 case TIOCLBIC: 230 case TIOCLSET: 231 case TIOCSTI: 232 /* this is reasonable, but impractical... 233 if ((flag & FWRITE) == 0) { 234 u.u_error = EBADF; 235 return (1); 236 } 237 */ 238 while (tp->t_line == NTTYDISC && 239 u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 240 (u.u_procp->p_flag&SVFORK) == 0 && 241 u.u_signal[SIGTTOU] != SIG_IGN && 242 u.u_signal[SIGTTOU] != SIG_HOLD 243 /* 244 && 245 (u.u_procp->p_flag&SDETACH)==0) { 246 */ 247 ) { 248 gsignal(u.u_procp->p_pgrp, SIGTTOU); 249 sleep((caddr_t)&lbolt, TTOPRI); 250 } 251 break; 252 } 253 254 /* 255 * Process the ioctl. 256 */ 257 switch(com) { 258 259 /* 260 * Get discipline number 261 */ 262 case TIOCGETD: 263 t = tp->t_line; 264 if (copyout((caddr_t)&t, addr, sizeof(t))) 265 u.u_error = EFAULT; 266 break; 267 268 /* 269 * Set line discipline 270 */ 271 case TIOCSETD: 272 if (copyin(addr, (caddr_t)&t, sizeof(t))) { 273 u.u_error = EFAULT; 274 break; 275 } 276 if (t >= nldisp) { 277 u.u_error = ENXIO; 278 break; 279 } 280 (void) spl5(); 281 if (tp->t_line) 282 (*linesw[tp->t_line].l_close)(tp); 283 if (t) 284 (*linesw[t].l_open)(dev, tp, addr); 285 if (u.u_error==0) 286 tp->t_line = t; 287 (void) spl0(); 288 break; 289 290 /* 291 * Prevent more opens on channel 292 */ 293 case TIOCEXCL: 294 tp->t_state |= TS_XCLUDE; 295 break; 296 297 case TIOCNXCL: 298 tp->t_state &= ~TS_XCLUDE; 299 break; 300 301 /* 302 * Set new parameters 303 */ 304 case TIOCSETP: 305 case TIOCSETN: 306 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 307 u.u_error = EFAULT; 308 return(1); 309 } 310 (void) spl5(); 311 if (tp->t_flags&RAW || iocb.sg_flags&RAW || 312 com == TIOCSETP) 313 wflushtty(tp); 314 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 315 if (iocb.sg_flags & CBREAK) { 316 catq(&tp->t_rawq, &tp->t_canq); 317 tq = tp->t_rawq; 318 tp->t_rawq = tp->t_canq; 319 tp->t_canq = tq; 320 } else { 321 tp->t_local |= LPENDIN; 322 ttwakeup(tp); 323 } 324 } 325 tp->t_ispeed = iocb.sg_ispeed; 326 tp->t_ospeed = iocb.sg_ospeed; 327 tp->t_erase = iocb.sg_erase; 328 tp->t_kill = iocb.sg_kill; 329 tp->t_flags = iocb.sg_flags; 330 if (tp->t_flags & RAW) { 331 tp->t_state &= ~TS_TTSTOP; 332 ttstart(tp); 333 } 334 (void) spl0(); 335 break; 336 337 /* 338 * Send current parameters to user 339 */ 340 case TIOCGETP: 341 iocb.sg_ispeed = tp->t_ispeed; 342 iocb.sg_ospeed = tp->t_ospeed; 343 iocb.sg_erase = tp->t_erase; 344 iocb.sg_kill = tp->t_kill; 345 iocb.sg_flags = tp->t_flags; 346 if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 347 u.u_error = EFAULT; 348 break; 349 350 /* 351 * Hang up line on last close 352 */ 353 case TIOCHPCL: 354 tp->t_state |= TS_HUPCLS; 355 break; 356 357 case TIOCFLUSH: { 358 int flags; 359 if (addr == 0) 360 flags = FREAD|FWRITE; 361 else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) { 362 u.u_error = EFAULT; 363 return(1); 364 } 365 flushtty(tp, flags); 366 break; 367 } 368 369 case FIONBIO: { 370 int nbio; 371 if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) { 372 u.u_error = EFAULT; 373 return(1); 374 } 375 if (nbio) 376 tp->t_state |= TS_NBIO; 377 else 378 tp->t_state &= ~TS_NBIO; 379 break; 380 } 381 382 case FIOASYNC: { 383 int async; 384 if (copyin(addr, (caddr_t)&async, sizeof (async))) { 385 u.u_error = EFAULT; 386 return(1); 387 } 388 if (async) 389 tp->t_state |= TS_ASYNC; 390 else 391 tp->t_state &= ~TS_ASYNC; 392 break; 393 } 394 395 /* 396 * Set and fetch special characters 397 */ 398 case TIOCSETC: 399 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 400 u.u_error = EFAULT; 401 break; 402 403 case TIOCGETC: 404 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 405 u.u_error = EFAULT; 406 break; 407 408 /* local ioctls */ 409 /* 410 * Set/get local special characters. 411 */ 412 case TIOCSLTC: 413 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 414 u.u_error = EFAULT; 415 break; 416 417 case TIOCGLTC: 418 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 419 u.u_error = EFAULT; 420 break; 421 422 /* 423 * Return number of characters immediately available. 424 */ 425 case FIONREAD: { 426 off_t nread = ttnread(tp); 427 if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 428 u.u_error = EFAULT; 429 break; 430 } 431 432 /* 433 * Should allow SPGRP and GPGRP only if tty open for reading. 434 */ 435 case TIOCSPGRP: 436 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 437 u.u_error = EFAULT; 438 break; 439 440 case TIOCGPGRP: 441 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 442 u.u_error = EFAULT; 443 break; 444 445 /* 446 * Modify local mode word. 447 */ 448 case TIOCLBIS: 449 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 450 u.u_error = EFAULT; 451 else 452 tp->t_local |= temp; 453 break; 454 455 case TIOCLBIC: 456 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 457 u.u_error = EFAULT; 458 else 459 tp->t_local &= ~temp; 460 break; 461 462 case TIOCLSET: 463 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 464 u.u_error = EFAULT; 465 else 466 tp->t_local = temp; 467 break; 468 469 case TIOCLGET: 470 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 471 u.u_error = EFAULT; 472 break; 473 474 /* 475 * Return number of characters in 476 * the output. 477 */ 478 case TIOCOUTQ: 479 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 480 u.u_error = EFAULT; 481 break; 482 483 /* 484 * Simulate typing of a character at the terminal. 485 */ 486 case TIOCSTI: 487 c = fubyte(addr); 488 if (u.u_uid && u.u_ttyp != tp || c < 0) 489 u.u_error = EFAULT; 490 else 491 (*linesw[tp->t_line].l_rint)(c, tp); 492 break; 493 494 case TIOCSTOP: 495 c = spl5(); 496 if ((tp->t_state & TS_TTSTOP) == 0) { 497 tp->t_state |= TS_TTSTOP; 498 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 499 } 500 splx(c); 501 break; 502 503 case TIOCSTART: 504 c = spl5(); 505 if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 506 tp->t_state &= ~TS_TTSTOP; 507 tp->t_local &= ~LFLUSHO; 508 ttstart(tp); 509 } 510 splx(c); 511 break; 512 513 /* end of locals */ 514 515 default: 516 return(0); 517 } 518 return(1); 519 } 520 521 ttnread(tp) 522 struct tty *tp; 523 { 524 int nread = 0; 525 526 if (tp->t_local & LPENDIN) 527 ttypend(tp); 528 nread = tp->t_canq.c_cc; 529 if (tp->t_flags & (RAW|CBREAK)) 530 nread += tp->t_rawq.c_cc; 531 return (nread); 532 } 533 534 ttselect(dev, rw) 535 dev_t dev; 536 int rw; 537 { 538 register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 539 int nread; 540 int s = spl5(); 541 542 switch (rw) { 543 544 case FREAD: 545 nread = ttnread(tp); 546 if (nread > 0) 547 goto win; 548 if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 549 tp->t_state |= TS_RCOLL; 550 else 551 tp->t_rsel = u.u_procp; 552 break; 553 554 case FWRITE: 555 if (tp->t_outq.c_cc <= TTLOWAT(tp)) 556 goto win; 557 if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 558 tp->t_state |= TS_WCOLL; 559 else 560 tp->t_wsel = u.u_procp; 561 break; 562 } 563 splx(s); 564 return (0); 565 win: 566 splx(s); 567 return (1); 568 } 569