1 /* tty.c 4.20 82/01/25 */ 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 (u.u_procp->p_flag&SDETACH)==0) { 244 gsignal(u.u_procp->p_pgrp, SIGTTOU); 245 sleep((caddr_t)&lbolt, TTOPRI); 246 } 247 break; 248 } 249 250 /* 251 * Process the ioctl. 252 */ 253 switch(com) { 254 255 /* 256 * Get discipline number 257 */ 258 case TIOCGETD: 259 t = tp->t_line; 260 if (copyout((caddr_t)&t, addr, sizeof(t))) 261 u.u_error = EFAULT; 262 break; 263 264 /* 265 * Set line discipline 266 */ 267 case TIOCSETD: 268 if (copyin(addr, (caddr_t)&t, sizeof(t))) { 269 u.u_error = EFAULT; 270 break; 271 } 272 if (t >= nldisp) { 273 u.u_error = ENXIO; 274 break; 275 } 276 (void) spl5(); 277 if (tp->t_line) 278 (*linesw[tp->t_line].l_close)(tp); 279 if (t) 280 (*linesw[t].l_open)(dev, tp, addr); 281 if (u.u_error==0) 282 tp->t_line = t; 283 (void) spl0(); 284 break; 285 286 /* 287 * Prevent more opens on channel 288 */ 289 case TIOCEXCL: 290 tp->t_state |= TS_XCLUDE; 291 break; 292 293 case TIOCNXCL: 294 tp->t_state &= ~TS_XCLUDE; 295 break; 296 297 /* 298 * Set new parameters 299 */ 300 case TIOCSETP: 301 case TIOCSETN: 302 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 303 u.u_error = EFAULT; 304 return(1); 305 } 306 (void) spl5(); 307 if (tp->t_flags&RAW || iocb.sg_flags&RAW || 308 com == TIOCSETP) 309 wflushtty(tp); 310 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 311 if (iocb.sg_flags & CBREAK) { 312 catq(&tp->t_rawq, &tp->t_canq); 313 tq = tp->t_rawq; 314 tp->t_rawq = tp->t_canq; 315 tp->t_canq = tq; 316 } else { 317 tp->t_local |= LPENDIN; 318 ttwakeup(tp); 319 } 320 } 321 tp->t_ispeed = iocb.sg_ispeed; 322 tp->t_ospeed = iocb.sg_ospeed; 323 tp->t_erase = iocb.sg_erase; 324 tp->t_kill = iocb.sg_kill; 325 tp->t_flags = iocb.sg_flags; 326 if (tp->t_flags & RAW) { 327 tp->t_state &= ~TS_TTSTOP; 328 ttstart(tp); 329 } 330 (void) spl0(); 331 break; 332 333 /* 334 * Send current parameters to user 335 */ 336 case TIOCGETP: 337 iocb.sg_ispeed = tp->t_ispeed; 338 iocb.sg_ospeed = tp->t_ospeed; 339 iocb.sg_erase = tp->t_erase; 340 iocb.sg_kill = tp->t_kill; 341 iocb.sg_flags = tp->t_flags; 342 if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 343 u.u_error = EFAULT; 344 break; 345 346 /* 347 * Hang up line on last close 348 */ 349 case TIOCHPCL: 350 tp->t_state |= TS_HUPCLS; 351 break; 352 353 case TIOCFLUSH: { 354 int flags; 355 if (addr == 0) 356 flags = FREAD|FWRITE; 357 else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) { 358 u.u_error = EFAULT; 359 return(1); 360 } 361 flushtty(tp, flags); 362 break; 363 } 364 365 case FIONBIO: { 366 int nbio; 367 if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) { 368 u.u_error = EFAULT; 369 return(1); 370 } 371 if (nbio) 372 tp->t_state |= TS_NBIO; 373 else 374 tp->t_state &= ~TS_NBIO; 375 break; 376 } 377 378 /* 379 * Set and fetch special characters 380 */ 381 case TIOCSETC: 382 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 383 u.u_error = EFAULT; 384 break; 385 386 case TIOCGETC: 387 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 388 u.u_error = EFAULT; 389 break; 390 391 /* local ioctls */ 392 /* 393 * Set/get local special characters. 394 */ 395 case TIOCSLTC: 396 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 397 u.u_error = EFAULT; 398 break; 399 400 case TIOCGLTC: 401 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 402 u.u_error = EFAULT; 403 break; 404 405 /* 406 * Return number of characters immediately available. 407 */ 408 case FIONREAD: { 409 off_t nread = ttnread(tp); 410 if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 411 u.u_error = EFAULT; 412 break; 413 } 414 415 /* 416 * Should allow SPGRP and GPGRP only if tty open for reading. 417 */ 418 case TIOCSPGRP: 419 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 420 u.u_error = EFAULT; 421 break; 422 423 case TIOCGPGRP: 424 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 425 u.u_error = EFAULT; 426 break; 427 428 /* 429 * Modify local mode word. 430 */ 431 case TIOCLBIS: 432 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 433 u.u_error = EFAULT; 434 else 435 tp->t_local |= temp; 436 break; 437 438 case TIOCLBIC: 439 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 440 u.u_error = EFAULT; 441 else 442 tp->t_local &= ~temp; 443 break; 444 445 case TIOCLSET: 446 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 447 u.u_error = EFAULT; 448 else 449 tp->t_local = temp; 450 break; 451 452 case TIOCLGET: 453 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 454 u.u_error = EFAULT; 455 break; 456 457 /* 458 * Return number of characters in 459 * the output. 460 */ 461 case TIOCOUTQ: 462 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 463 u.u_error = EFAULT; 464 break; 465 466 /* 467 * Simulate typing of a character at the terminal. 468 */ 469 case TIOCSTI: 470 c = fubyte(addr); 471 if (u.u_uid && u.u_ttyp != tp || c < 0) 472 u.u_error = EFAULT; 473 else 474 (*linesw[tp->t_line].l_rint)(c, tp); 475 break; 476 477 case TIOCSTOP: 478 c = spl5(); 479 if ((tp->t_state & TS_TTSTOP) == 0) { 480 tp->t_state |= TS_TTSTOP; 481 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 482 } 483 splx(c); 484 break; 485 486 case TIOCSTART: 487 c = spl5(); 488 if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 489 tp->t_state &= ~TS_TTSTOP; 490 tp->t_local &= ~LFLUSHO; 491 ttstart(tp); 492 } 493 splx(c); 494 break; 495 496 /* end of locals */ 497 498 default: 499 return(0); 500 } 501 return(1); 502 } 503 504 ttnread(tp) 505 struct tty *tp; 506 { 507 int nread = 0; 508 509 if (tp->t_local & LPENDIN) 510 ttypend(tp); 511 nread = tp->t_canq.c_cc; 512 if (tp->t_flags & (RAW|CBREAK)) 513 nread += tp->t_rawq.c_cc; 514 return (nread); 515 } 516 517 ttselect(dev, rw) 518 dev_t dev; 519 int rw; 520 { 521 register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 522 int nread; 523 int s = spl5(); 524 525 switch (rw) { 526 527 case FREAD: 528 nread = ttnread(tp); 529 if (nread > 0) 530 goto win; 531 if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 532 tp->t_state |= TS_RCOLL; 533 else 534 tp->t_rsel = u.u_procp; 535 break; 536 537 case FWRITE: 538 if (tp->t_outq.c_cc <= TTLOWAT(tp)) 539 goto win; 540 if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 541 tp->t_state |= TS_WCOLL; 542 else 543 tp->t_wsel = u.u_procp; 544 break; 545 } 546 splx(s); 547 return (0); 548 win: 549 splx(s); 550 return (1); 551 } 552