1 /* tty.c 4.19 82/01/24 */ 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)(tp); 91 tp->t_state |= TS_ASLEEP; 92 sleep((caddr_t)&tp->t_outq, TTOPRI); 93 } 94 flushtty(tp, FREAD); 95 (void) spl0(); 96 } 97 98 /* 99 * flush all TTY queues 100 */ 101 flushtty(tp, rw) 102 register struct tty *tp; 103 { 104 register s; 105 106 s = spl6(); 107 if (rw & FREAD) { 108 while (getc(&tp->t_canq) >= 0) 109 ; 110 wakeup((caddr_t)&tp->t_rawq); 111 } 112 if (rw & FWRITE) { 113 wakeup((caddr_t)&tp->t_outq); 114 tp->t_state &= ~TS_TTSTOP; 115 (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 116 while (getc(&tp->t_outq) >= 0) 117 ; 118 } 119 if (rw & FREAD) { 120 while (getc(&tp->t_rawq) >= 0) 121 ; 122 tp->t_delct = 0; 123 tp->t_rocount = 0; /* local */ 124 tp->t_rocol = 0; 125 tp->t_lstate = 0; 126 } 127 splx(s); 128 } 129 130 /* 131 * Send stop character on input overflow. 132 */ 133 ttyblock(tp) 134 register struct tty *tp; 135 { 136 register x; 137 x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 138 if (tp->t_rawq.c_cc > TTYHOG) { 139 flushtty(tp, FREAD|FWRITE); 140 tp->t_state &= ~TS_TBLOCK; 141 } 142 if (x >= TTYHOG/2) { 143 if (putc(tun.t_stopc, &tp->t_outq)==0) { 144 tp->t_state |= TS_TBLOCK; 145 tp->t_char++; 146 ttstart(tp); 147 } 148 } 149 } 150 151 /* 152 * Restart typewriter output following a delay 153 * timeout. 154 * The name of the routine is passed to the timeout 155 * subroutine and it is called during a clock interrupt. 156 */ 157 ttrstrt(tp) 158 register struct tty *tp; 159 { 160 161 if (tp == 0) { 162 printf("ttrstrt: arg was 0!\n"); 163 return; 164 } 165 tp->t_state &= ~TS_TIMEOUT; 166 ttstart(tp); 167 } 168 169 /* 170 * Start output on the typewriter. It is used from the top half 171 * after some characters have been put on the output queue, 172 * from the interrupt routine to transmit the next 173 * character, and after a timeout has finished. 174 */ 175 ttstart(tp) 176 register struct tty *tp; 177 { 178 register s; 179 180 s = spl5(); 181 if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0) 182 (*tp->t_oproc)(tp); 183 splx(s); 184 } 185 186 /* 187 * Common code for tty ioctls. 188 */ 189 /*ARGSUSED*/ 190 ttioctl(tp, com, addr, flag) 191 register struct tty *tp; 192 caddr_t addr; 193 { 194 int dev; 195 unsigned t; 196 struct sgttyb iocb; 197 struct clist tq; 198 extern int nldisp; 199 register c; 200 int temp; 201 202 /* 203 * This is especially so that isatty() will 204 * fail when carrier is gone. 205 */ 206 if ((tp->t_state&TS_CARR_ON) == 0) { 207 u.u_error = EBADF; 208 return (1); 209 } 210 211 dev = tp->t_dev; 212 /* 213 * If the ioctl involves modification, 214 * insist on being able to write the device, 215 * and hang if in the background. 216 */ 217 switch(com) { 218 219 case TIOCSETD: 220 case TIOCSETP: 221 case TIOCSETN: 222 case TIOCFLUSH: 223 case TIOCSETC: 224 case TIOCSLTC: 225 case TIOCSPGRP: 226 case TIOCLBIS: 227 case TIOCLBIC: 228 case TIOCLSET: 229 case TIOCSTI: 230 /* this is reasonable, but impractical... 231 if ((flag & FWRITE) == 0) { 232 u.u_error = EBADF; 233 return (1); 234 } 235 */ 236 while (tp->t_line == NTTYDISC && 237 u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 238 (u.u_procp->p_flag&SVFORK) == 0 && 239 u.u_signal[SIGTTOU] != SIG_IGN && 240 u.u_signal[SIGTTOU] != SIG_HOLD && 241 (u.u_procp->p_flag&SDETACH)==0) { 242 gsignal(u.u_procp->p_pgrp, SIGTTOU); 243 sleep((caddr_t)&lbolt, TTOPRI); 244 } 245 break; 246 } 247 248 /* 249 * Process the ioctl. 250 */ 251 switch(com) { 252 253 /* 254 * Get discipline number 255 */ 256 case TIOCGETD: 257 t = tp->t_line; 258 if (copyout((caddr_t)&t, addr, sizeof(t))) 259 u.u_error = EFAULT; 260 break; 261 262 /* 263 * Set line discipline 264 */ 265 case TIOCSETD: 266 if (copyin(addr, (caddr_t)&t, sizeof(t))) { 267 u.u_error = EFAULT; 268 break; 269 } 270 if (t >= nldisp) { 271 u.u_error = ENXIO; 272 break; 273 } 274 (void) spl5(); 275 if (tp->t_line) 276 (*linesw[tp->t_line].l_close)(tp); 277 if (t) 278 (*linesw[t].l_open)(dev, tp, addr); 279 if (u.u_error==0) 280 tp->t_line = t; 281 (void) spl0(); 282 break; 283 284 /* 285 * Prevent more opens on channel 286 */ 287 case TIOCEXCL: 288 tp->t_state |= TS_XCLUDE; 289 break; 290 291 case TIOCNXCL: 292 tp->t_state &= ~TS_XCLUDE; 293 break; 294 295 /* 296 * Set new parameters 297 */ 298 case TIOCSETP: 299 case TIOCSETN: 300 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 301 u.u_error = EFAULT; 302 return(1); 303 } 304 (void) spl5(); 305 if (tp->t_flags&RAW || iocb.sg_flags&RAW || 306 com == TIOCSETP) 307 wflushtty(tp); 308 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 309 if (iocb.sg_flags & CBREAK) { 310 catq(&tp->t_rawq, &tp->t_canq); 311 tq = tp->t_rawq; 312 tp->t_rawq = tp->t_canq; 313 tp->t_canq = tq; 314 } else { 315 tp->t_local |= LPENDIN; 316 ttwakeup(tp); 317 } 318 } 319 tp->t_ispeed = iocb.sg_ispeed; 320 tp->t_ospeed = iocb.sg_ospeed; 321 tp->t_erase = iocb.sg_erase; 322 tp->t_kill = iocb.sg_kill; 323 tp->t_flags = iocb.sg_flags; 324 if (tp->t_flags & RAW) { 325 tp->t_state &= ~TS_TTSTOP; 326 ttstart(tp); 327 } 328 (void) spl0(); 329 break; 330 331 /* 332 * Send current parameters to user 333 */ 334 case TIOCGETP: 335 iocb.sg_ispeed = tp->t_ispeed; 336 iocb.sg_ospeed = tp->t_ospeed; 337 iocb.sg_erase = tp->t_erase; 338 iocb.sg_kill = tp->t_kill; 339 iocb.sg_flags = tp->t_flags; 340 if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 341 u.u_error = EFAULT; 342 break; 343 344 /* 345 * Hang up line on last close 346 */ 347 case TIOCHPCL: 348 tp->t_state |= TS_HUPCLS; 349 break; 350 351 case TIOCFLUSH: { 352 int flags; 353 if (addr == 0) 354 flags = FREAD|FWRITE; 355 else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) { 356 u.u_error = EFAULT; 357 return(1); 358 } 359 flushtty(tp, flags); 360 break; 361 } 362 363 case FIONBIO: { 364 int nbio; 365 if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) { 366 u.u_error = EFAULT; 367 return(1); 368 } 369 if (nbio) 370 tp->t_state |= TS_NBIO; 371 else 372 tp->t_state &= ~TS_NBIO; 373 break; 374 } 375 376 /* 377 * Set and fetch special characters 378 */ 379 case TIOCSETC: 380 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 381 u.u_error = EFAULT; 382 break; 383 384 case TIOCGETC: 385 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 386 u.u_error = EFAULT; 387 break; 388 389 /* local ioctls */ 390 /* 391 * Set/get local special characters. 392 */ 393 case TIOCSLTC: 394 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 395 u.u_error = EFAULT; 396 break; 397 398 case TIOCGLTC: 399 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 400 u.u_error = EFAULT; 401 break; 402 403 /* 404 * Return number of characters immediately available. 405 */ 406 case FIONREAD: { 407 off_t nread = ttnread(tp); 408 if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 409 u.u_error = EFAULT; 410 break; 411 } 412 413 /* 414 * Should allow SPGRP and GPGRP only if tty open for reading. 415 */ 416 case TIOCSPGRP: 417 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 418 u.u_error = EFAULT; 419 break; 420 421 case TIOCGPGRP: 422 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 423 u.u_error = EFAULT; 424 break; 425 426 /* 427 * Modify local mode word. 428 */ 429 case TIOCLBIS: 430 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 431 u.u_error = EFAULT; 432 else 433 tp->t_local |= temp; 434 break; 435 436 case TIOCLBIC: 437 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 438 u.u_error = EFAULT; 439 else 440 tp->t_local &= ~temp; 441 break; 442 443 case TIOCLSET: 444 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 445 u.u_error = EFAULT; 446 else 447 tp->t_local = temp; 448 break; 449 450 case TIOCLGET: 451 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 452 u.u_error = EFAULT; 453 break; 454 455 /* 456 * Return number of characters in 457 * the output. 458 */ 459 case TIOCOUTQ: 460 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 461 u.u_error = EFAULT; 462 break; 463 464 /* 465 * Simulate typing of a character at the terminal. 466 */ 467 case TIOCSTI: 468 c = fubyte(addr); 469 if (u.u_uid && u.u_ttyp != tp || c < 0) 470 u.u_error = EFAULT; 471 else 472 (*linesw[tp->t_line].l_rint)(c, tp); 473 break; 474 475 case TIOCSTOP: 476 c = spl5(); 477 if ((tp->t_state & TS_TTSTOP) == 0) { 478 tp->t_state |= TS_TTSTOP; 479 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 480 } 481 splx(c); 482 break; 483 484 case TIOCSTART: 485 c = spl5(); 486 if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 487 tp->t_state &= ~TS_TTSTOP; 488 tp->t_local &= ~LFLUSHO; 489 ttstart(tp); 490 } 491 splx(c); 492 break; 493 494 /* end of locals */ 495 496 default: 497 return(0); 498 } 499 return(1); 500 } 501 502 ttnread(tp) 503 struct tty *tp; 504 { 505 int nread = 0; 506 507 if (tp->t_local & LPENDIN) 508 ttypend(tp); 509 nread = tp->t_canq.c_cc; 510 if (tp->t_flags & (RAW|CBREAK)) 511 nread += tp->t_rawq.c_cc; 512 return (nread); 513 } 514 515 ttselect(dev, rw) 516 dev_t dev; 517 int rw; 518 { 519 register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 520 int nread; 521 int s = spl5(); 522 523 switch (rw) { 524 525 case FREAD: 526 nread = ttnread(tp); 527 if (nread > 0) 528 goto win; 529 if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 530 tp->t_state |= TS_RCOLL; 531 else 532 tp->t_rsel = u.u_procp; 533 break; 534 535 case FWRITE: 536 if (tp->t_outq.c_cc <= TTLOWAT(tp)) 537 goto win; 538 if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 539 tp->t_state |= TS_WCOLL; 540 else 541 tp->t_wsel = u.u_procp; 542 break; 543 } 544 splx(s); 545 return (0); 546 win: 547 splx(s); 548 return (1); 549 } 550