1 /* tty.c 3.18 09/25/80 */ 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/mx.h" 13 #include "../h/inode.h" 14 #include "../h/file.h" 15 #include "../h/reg.h" 16 #include "../h/conf.h" 17 #include "../h/buf.h" 18 #include "../h/dk.h" 19 20 char partab[]; 21 22 /* 23 * When running dz's using only SAE (silo alarm) on input 24 * it is necessary to call dzrint() at clock interrupt time. 25 * This is unsafe unless spl5()s in tty code are changed to 26 * spl6()s to block clock interrupts. Note that the dh driver 27 * currently in use works the same way as the dz, even though 28 * we could try to more intelligently manage its silo. 29 * Thus don't take this out if you have no dz's unless you 30 * change clock.c and dhtimer(). 31 */ 32 #define spl5 spl6 33 34 /* 35 * Input mapping table-- if an entry is non-zero, when the 36 * corresponding character is typed preceded by "\" the escape 37 * sequence is replaced by the table value. Mostly used for 38 * upper-case only terminals. 39 */ 40 41 char maptab[] ={ 42 000,000,000,000,000,000,000,000, 43 000,000,000,000,000,000,000,000, 44 000,000,000,000,000,000,000,000, 45 000,000,000,000,000,000,000,000, 46 000,'|',000,000,000,000,000,'`', 47 '{','}',000,000,000,000,000,000, 48 000,000,000,000,000,000,000,000, 49 000,000,000,000,000,000,000,000, 50 000,000,000,000,000,000,000,000, 51 000,000,000,000,000,000,000,000, 52 000,000,000,000,000,000,000,000, 53 000,000,000,000,000,000,'~',000, 54 000,'A','B','C','D','E','F','G', 55 'H','I','J','K','L','M','N','O', 56 'P','Q','R','S','T','U','V','W', 57 'X','Y','Z',000,000,000,000,000, 58 }; 59 60 #define OBUFSIZ 100 61 62 /* 63 * set default control characters. 64 */ 65 ttychars(tp) 66 register struct tty *tp; 67 { 68 69 tun.t_intrc = CINTR; 70 tun.t_quitc = CQUIT; 71 tun.t_startc = CSTART; 72 tun.t_stopc = CSTOP; 73 tun.t_eofc = CEOT; 74 tun.t_brkc = CBRK; 75 tp->t_erase = CERASE; 76 tp->t_kill = CKILL; 77 /* begin local */ 78 tlun.t_suspc = CTRL(z); 79 tlun.t_dsuspc = CTRL(y); 80 tlun.t_rprntc = CTRL(r); 81 tlun.t_flushc = CTRL(o); 82 tlun.t_werasc = CTRL(w); 83 tlun.t_lnextc = CTRL(v); 84 tlun.t_lintr = CTRL(c); 85 tlun.t_lerase = CTRL(h); 86 tlun.t_lkill = CTRL(u); 87 tp->t_local = 0; 88 tp->t_lstate = 0; 89 /* end local */ 90 } 91 92 /* 93 * Wait for output to drain, then flush input waiting. 94 */ 95 wflushtty(tp) 96 register struct tty *tp; 97 { 98 99 (void) spl5(); 100 while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 101 (*tp->t_oproc)(tp); 102 tp->t_state |= ASLEEP; 103 sleep((caddr_t)&tp->t_outq, TTOPRI); 104 } 105 flushtty(tp, FREAD|FWRITE); 106 (void) spl0(); 107 } 108 109 /* 110 * flush all TTY queues 111 */ 112 flushtty(tp, rw) 113 register struct tty *tp; 114 { 115 register s; 116 117 if (tp->t_line == NETLDISC) 118 return; 119 s = spl6(); 120 if (rw & FREAD) { 121 while (getc(&tp->t_canq) >= 0) 122 ; 123 wakeup((caddr_t)&tp->t_rawq); 124 } 125 if (rw & FWRITE) { 126 wakeup((caddr_t)&tp->t_outq); 127 tp->t_state &= ~TTSTOP; 128 (*cdevsw[major(tp->t_dev)].d_stop)(tp); 129 while (getc(&tp->t_outq) >= 0) 130 ; 131 } 132 if (rw & FREAD) { 133 while (getc(&tp->t_rawq) >= 0) 134 ; 135 tp->t_delct = 0; 136 tp->t_rocount = 0; /* local */ 137 tp->t_rocol = 0; 138 tp->t_lstate = 0; 139 } 140 splx(s); 141 } 142 143 /* 144 * Send stop character on input overflow. 145 */ 146 ttyblock(tp) 147 register struct tty *tp; 148 { 149 register x; 150 x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 151 if (tp->t_rawq.c_cc > TTYHOG) { 152 flushtty(tp, FREAD|FWRITE); 153 tp->t_state &= ~TBLOCK; 154 } 155 if (x >= TTYHOG/2) { 156 if (putc(tun.t_stopc, &tp->t_outq)==0) { 157 tp->t_state |= TBLOCK; 158 tp->t_char++; 159 ttstart(tp); 160 } 161 } 162 } 163 164 /* 165 * Restart typewriter output following a delay 166 * timeout. 167 * The name of the routine is passed to the timeout 168 * subroutine and it is called during a clock interrupt. 169 */ 170 ttrstrt(tp) 171 register struct tty *tp; 172 { 173 174 tp->t_state &= ~TIMEOUT; 175 ttstart(tp); 176 } 177 178 /* 179 * Start output on the typewriter. It is used from the top half 180 * after some characters have been put on the output queue, 181 * from the interrupt routine to transmit the next 182 * character, and after a timeout has finished. 183 */ 184 ttstart(tp) 185 register struct tty *tp; 186 { 187 register s; 188 189 s = spl5(); 190 if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 191 (*tp->t_oproc)(tp); 192 splx(s); 193 } 194 195 /* 196 * Common code for tty ioctls. 197 */ 198 ttioctl(com, tp, addr, dev, flag) 199 register struct tty *tp; 200 caddr_t addr; 201 { 202 unsigned t; 203 struct sgttyb iocb; 204 struct clist tq; 205 extern int nldisp; 206 register c; 207 int temp; 208 209 /* 210 * This is especially so that isatty() will 211 * fail when carrier is gone. 212 */ 213 if ((tp->t_state&CARR_ON) == 0) { 214 u.u_error = EBADF; 215 return (1); 216 } 217 218 /* 219 * If the ioctl involves modification, 220 * insist on being able to write the device, 221 * and hang if in the background. 222 */ 223 switch(com) { 224 225 case TIOCSETD: 226 case TIOCSETP: 227 case TIOCSETN: 228 case TIOCFLUSH: 229 case TIOCSETC: 230 case TIOCSLTC: 231 case TIOCSPGRP: 232 case TIOCLBIS: 233 case TIOCLBIC: 234 case TIOCLSET: 235 case TIOCSTI: 236 /* this is reasonable, but impractical... 237 if ((flag & FWRITE) == 0) { 238 u.u_error = EBADF; 239 return (1); 240 } 241 */ 242 while (tp->t_line == NTTYDISC && 243 u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 244 (u.u_procp->p_flag&SVFORK) == 0 && 245 u.u_signal[SIGTTOU] != SIG_IGN && 246 u.u_signal[SIGTTOU] != SIG_HOLD && 247 (u.u_procp->p_flag&SDETACH)==0) { 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 |= XCLUDE; 295 break; 296 297 case TIOCNXCL: 298 tp->t_state &= ~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_line == 0) { 312 if (com == TIOCSETP) 313 wflushtty(tp); 314 while (canon(tp)>=0) 315 ; 316 } else if (tp->t_line == NTTYDISC) { 317 if (tp->t_flags&RAW || iocb.sg_flags&RAW || 318 com == TIOCSETP) 319 wflushtty(tp); 320 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 321 if (iocb.sg_flags & CBREAK) { 322 catq(&tp->t_rawq, &tp->t_canq); 323 tq = tp->t_rawq; 324 tp->t_rawq = tp->t_canq; 325 tp->t_canq = tq; 326 } else { 327 tp->t_local |= LPENDIN; 328 if (tp->t_canq.c_cc) 329 panic("ioccom canq"); 330 if (tp->t_chan) 331 (void) sdata(tp->t_chan); 332 else 333 wakeup((caddr_t)&tp->t_rawq); 334 } 335 } 336 } 337 if ((tp->t_state&SPEEDS)==0) { 338 tp->t_ispeed = iocb.sg_ispeed; 339 tp->t_ospeed = iocb.sg_ospeed; 340 } 341 tp->t_erase = iocb.sg_erase; 342 tp->t_kill = iocb.sg_kill; 343 tp->t_flags = iocb.sg_flags; 344 (void) spl0(); 345 break; 346 347 /* 348 * Send current parameters to user 349 */ 350 case TIOCGETP: 351 iocb.sg_ispeed = tp->t_ispeed; 352 iocb.sg_ospeed = tp->t_ospeed; 353 iocb.sg_erase = tp->t_erase; 354 iocb.sg_kill = tp->t_kill; 355 iocb.sg_flags = tp->t_flags; 356 if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 357 u.u_error = EFAULT; 358 break; 359 360 /* 361 * Hang up line on last close 362 */ 363 case TIOCHPCL: 364 tp->t_state |= HUPCLS; 365 break; 366 367 case TIOCFLUSH: 368 flushtty(tp, FREAD|FWRITE); 369 break; 370 371 /* 372 * Ioctl entries to line discipline 373 */ 374 case DIOCSETP: 375 case DIOCGETP: 376 if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 377 u.u_error = ENOTTY; 378 break; 379 380 /* 381 * Set and fetch special characters 382 */ 383 case TIOCSETC: 384 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 385 u.u_error = EFAULT; 386 break; 387 388 case TIOCGETC: 389 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 390 u.u_error = EFAULT; 391 break; 392 393 /* local ioctls */ 394 /* 395 * Set/get local special characters. 396 */ 397 case TIOCSLTC: 398 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 399 u.u_error = EFAULT; 400 break; 401 402 case TIOCGLTC: 403 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 404 u.u_error = EFAULT; 405 break; 406 407 /* 408 * Return number of characters immediately available. 409 */ 410 case FIONREAD: { 411 off_t nread; 412 413 switch (tp->t_line) { 414 415 case NETLDISC: 416 nread = tp->t_rec ? tp->t_inbuf : 0; 417 break; 418 419 case 0: 420 (void) spl5(); 421 while (canon(tp)>=0) 422 ; 423 (void) spl0(); 424 /* fall into ... */ 425 426 case NTTYDISC: 427 nread = tp->t_canq.c_cc; 428 if (tp->t_flags & (RAW|CBREAK)) 429 nread += tp->t_rawq.c_cc; 430 break; 431 432 } 433 if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 434 u.u_error = EFAULT; 435 break; 436 } 437 438 /* 439 * Should allow SPGRP and GPGRP only if tty open for reading. 440 */ 441 case TIOCSPGRP: 442 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 443 u.u_error = EFAULT; 444 break; 445 446 case TIOCGPGRP: 447 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 448 u.u_error = EFAULT; 449 break; 450 451 /* 452 * Modify local mode word. 453 */ 454 case TIOCLBIS: 455 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 456 u.u_error = EFAULT; 457 else 458 tp->t_local |= temp; 459 break; 460 461 case TIOCLBIC: 462 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 463 u.u_error = EFAULT; 464 else 465 tp->t_local &= ~temp; 466 break; 467 468 case TIOCLSET: 469 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 470 u.u_error = EFAULT; 471 else 472 tp->t_local = temp; 473 break; 474 475 case TIOCLGET: 476 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 477 u.u_error = EFAULT; 478 break; 479 480 /* 481 * Return number of characters in 482 * the output. 483 */ 484 case TIOCOUTQ: 485 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 486 u.u_error = EFAULT; 487 break; 488 489 /* 490 * Simulate typing of a character at the terminal. 491 */ 492 case TIOCSTI: 493 c = fubyte(addr); 494 if (u.u_uid && u.u_ttyp != tp || c < 0) 495 u.u_error = EFAULT; 496 else 497 (*linesw[tp->t_line].l_rint)(c, tp); 498 break; 499 /* end of locals */ 500 501 default: 502 return(0); 503 } 504 return(1); 505 } 506