1 /* tty.c 4.2 11/09/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 short tthiwat[16] = 61 { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; 62 short ttlowat[16] = 63 { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 64 65 #define OBUFSIZ 100 66 67 /* 68 * set default control characters. 69 */ 70 ttychars(tp) 71 register struct tty *tp; 72 { 73 74 tun.t_intrc = CINTR; 75 tun.t_quitc = CQUIT; 76 tun.t_startc = CSTART; 77 tun.t_stopc = CSTOP; 78 tun.t_eofc = CEOT; 79 tun.t_brkc = CBRK; 80 tp->t_erase = CERASE; 81 tp->t_kill = CKILL; 82 /* begin local */ 83 tlun.t_suspc = CTRL(z); 84 tlun.t_dsuspc = CTRL(y); 85 tlun.t_rprntc = CTRL(r); 86 tlun.t_flushc = CTRL(o); 87 tlun.t_werasc = CTRL(w); 88 tlun.t_lnextc = CTRL(v); 89 tp->t_local = 0; 90 tp->t_lstate = 0; 91 /* end local */ 92 } 93 94 /* 95 * Wait for output to drain, then flush input waiting. 96 */ 97 wflushtty(tp) 98 register struct tty *tp; 99 { 100 101 (void) spl5(); 102 while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 103 (*tp->t_oproc)(tp); 104 tp->t_state |= ASLEEP; 105 sleep((caddr_t)&tp->t_outq, TTOPRI); 106 } 107 flushtty(tp, FREAD|FWRITE); 108 (void) spl0(); 109 } 110 111 /* 112 * flush all TTY queues 113 */ 114 flushtty(tp, rw) 115 register struct tty *tp; 116 { 117 register s; 118 119 if (tp->t_line == NETLDISC) 120 return; 121 s = spl6(); 122 if (rw & FREAD) { 123 while (getc(&tp->t_canq) >= 0) 124 ; 125 wakeup((caddr_t)&tp->t_rawq); 126 } 127 if (rw & FWRITE) { 128 wakeup((caddr_t)&tp->t_outq); 129 tp->t_state &= ~TTSTOP; 130 (*cdevsw[major(tp->t_dev)].d_stop)(tp); 131 while (getc(&tp->t_outq) >= 0) 132 ; 133 } 134 if (rw & FREAD) { 135 while (getc(&tp->t_rawq) >= 0) 136 ; 137 tp->t_delct = 0; 138 tp->t_rocount = 0; /* local */ 139 tp->t_rocol = 0; 140 tp->t_lstate = 0; 141 } 142 splx(s); 143 } 144 145 /* 146 * Send stop character on input overflow. 147 */ 148 ttyblock(tp) 149 register struct tty *tp; 150 { 151 register x; 152 x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 153 if (tp->t_rawq.c_cc > TTYHOG) { 154 flushtty(tp, FREAD|FWRITE); 155 tp->t_state &= ~TBLOCK; 156 } 157 if (x >= TTYHOG/2) { 158 if (putc(tun.t_stopc, &tp->t_outq)==0) { 159 tp->t_state |= TBLOCK; 160 tp->t_char++; 161 ttstart(tp); 162 } 163 } 164 } 165 166 /* 167 * Restart typewriter output following a delay 168 * timeout. 169 * The name of the routine is passed to the timeout 170 * subroutine and it is called during a clock interrupt. 171 */ 172 ttrstrt(tp) 173 register struct tty *tp; 174 { 175 176 tp->t_state &= ~TIMEOUT; 177 ttstart(tp); 178 } 179 180 /* 181 * Start output on the typewriter. It is used from the top half 182 * after some characters have been put on the output queue, 183 * from the interrupt routine to transmit the next 184 * character, and after a timeout has finished. 185 */ 186 ttstart(tp) 187 register struct tty *tp; 188 { 189 register s; 190 191 s = spl5(); 192 if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 193 (*tp->t_oproc)(tp); 194 splx(s); 195 } 196 197 /* 198 * Common code for tty ioctls. 199 */ 200 /*ARGSUSED*/ 201 ttioctl(com, tp, addr, dev, flag) 202 register struct tty *tp; 203 caddr_t addr; 204 { 205 unsigned t; 206 struct sgttyb iocb; 207 struct clist tq; 208 extern int nldisp; 209 register c; 210 int temp; 211 212 /* 213 * This is especially so that isatty() will 214 * fail when carrier is gone. 215 */ 216 if ((tp->t_state&CARR_ON) == 0) { 217 u.u_error = EBADF; 218 return (1); 219 } 220 221 /* 222 * If the ioctl involves modification, 223 * insist on being able to write the device, 224 * and hang if in the background. 225 */ 226 switch(com) { 227 228 case TIOCSETD: 229 case TIOCSETP: 230 case TIOCSETN: 231 case TIOCFLUSH: 232 case TIOCSETC: 233 case TIOCSLTC: 234 case TIOCSPGRP: 235 case TIOCLBIS: 236 case TIOCLBIC: 237 case TIOCLSET: 238 case TIOCSTI: 239 /* this is reasonable, but impractical... 240 if ((flag & FWRITE) == 0) { 241 u.u_error = EBADF; 242 return (1); 243 } 244 */ 245 while (tp->t_line == NTTYDISC && 246 u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 247 (u.u_procp->p_flag&SVFORK) == 0 && 248 u.u_signal[SIGTTOU] != SIG_IGN && 249 u.u_signal[SIGTTOU] != SIG_HOLD && 250 (u.u_procp->p_flag&SDETACH)==0) { 251 gsignal(u.u_procp->p_pgrp, SIGTTOU); 252 sleep((caddr_t)&lbolt, TTOPRI); 253 } 254 break; 255 } 256 257 /* 258 * Process the ioctl. 259 */ 260 switch(com) { 261 262 /* 263 * Get discipline number 264 */ 265 case TIOCGETD: 266 t = tp->t_line; 267 if (copyout((caddr_t)&t, addr, sizeof(t))) 268 u.u_error = EFAULT; 269 break; 270 271 /* 272 * Set line discipline 273 */ 274 case TIOCSETD: 275 if (copyin(addr, (caddr_t)&t, sizeof(t))) { 276 u.u_error = EFAULT; 277 break; 278 } 279 if (t >= nldisp) { 280 u.u_error = ENXIO; 281 break; 282 } 283 (void) spl5(); 284 if (tp->t_line) 285 (*linesw[tp->t_line].l_close)(tp); 286 if (t) 287 (*linesw[t].l_open)(dev, tp, addr); 288 if (u.u_error==0) 289 tp->t_line = t; 290 (void) spl0(); 291 break; 292 293 /* 294 * Prevent more opens on channel 295 */ 296 case TIOCEXCL: 297 tp->t_state |= XCLUDE; 298 break; 299 300 case TIOCNXCL: 301 tp->t_state &= ~XCLUDE; 302 break; 303 304 /* 305 * Set new parameters 306 */ 307 case TIOCSETP: 308 case TIOCSETN: 309 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 310 u.u_error = EFAULT; 311 return(1); 312 } 313 (void) spl5(); 314 if (tp->t_line == 0) { 315 if (com == TIOCSETP) 316 wflushtty(tp); 317 while (canon(tp)>=0) 318 ; 319 #ifdef notdef 320 wakeup((caddr_t)&tp->t_rawq); 321 #endif 322 } else if (tp->t_line == NTTYDISC) { 323 if (tp->t_flags&RAW || iocb.sg_flags&RAW || 324 com == TIOCSETP) 325 wflushtty(tp); 326 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 327 if (iocb.sg_flags & CBREAK) { 328 catq(&tp->t_rawq, &tp->t_canq); 329 tq = tp->t_rawq; 330 tp->t_rawq = tp->t_canq; 331 tp->t_canq = tq; 332 } else { 333 tp->t_local |= LPENDIN; 334 if (tp->t_canq.c_cc) 335 panic("ioccom canq"); 336 #ifdef notdef 337 if (tp->t_chan) 338 (void) sdata(tp->t_chan); 339 else 340 #endif 341 wakeup((caddr_t)&tp->t_rawq); 342 } 343 } 344 } 345 if ((tp->t_state&SPEEDS)==0) { 346 tp->t_ispeed = iocb.sg_ispeed; 347 tp->t_ospeed = iocb.sg_ospeed; 348 } 349 tp->t_erase = iocb.sg_erase; 350 tp->t_kill = iocb.sg_kill; 351 tp->t_flags = iocb.sg_flags; 352 (void) spl0(); 353 break; 354 355 /* 356 * Send current parameters to user 357 */ 358 case TIOCGETP: 359 iocb.sg_ispeed = tp->t_ispeed; 360 iocb.sg_ospeed = tp->t_ospeed; 361 iocb.sg_erase = tp->t_erase; 362 iocb.sg_kill = tp->t_kill; 363 iocb.sg_flags = tp->t_flags; 364 if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 365 u.u_error = EFAULT; 366 break; 367 368 /* 369 * Hang up line on last close 370 */ 371 case TIOCHPCL: 372 tp->t_state |= HUPCLS; 373 break; 374 375 case TIOCFLUSH: 376 flushtty(tp, FREAD|FWRITE); 377 break; 378 379 /* 380 * Ioctl entries to line discipline 381 */ 382 case DIOCSETP: 383 case DIOCGETP: 384 if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 385 u.u_error = ENOTTY; 386 break; 387 388 /* 389 * Set and fetch special characters 390 */ 391 case TIOCSETC: 392 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 393 u.u_error = EFAULT; 394 break; 395 396 case TIOCGETC: 397 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 398 u.u_error = EFAULT; 399 break; 400 401 /* local ioctls */ 402 /* 403 * Set/get local special characters. 404 */ 405 case TIOCSLTC: 406 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 407 u.u_error = EFAULT; 408 break; 409 410 case TIOCGLTC: 411 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 412 u.u_error = EFAULT; 413 break; 414 415 /* 416 * Return number of characters immediately available. 417 */ 418 case FIONREAD: { 419 off_t nread; 420 421 switch (tp->t_line) { 422 423 case NETLDISC: 424 nread = tp->t_rec ? tp->t_inbuf : 0; 425 break; 426 427 case 0: 428 (void) spl5(); 429 while (canon(tp)>=0) 430 ; 431 (void) spl0(); 432 /* fall into ... */ 433 434 case NTTYDISC: 435 nread = tp->t_canq.c_cc; 436 if (tp->t_flags & (RAW|CBREAK)) 437 nread += tp->t_rawq.c_cc; 438 break; 439 440 } 441 if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 442 u.u_error = EFAULT; 443 break; 444 } 445 446 /* 447 * Should allow SPGRP and GPGRP only if tty open for reading. 448 */ 449 case TIOCSPGRP: 450 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 451 u.u_error = EFAULT; 452 break; 453 454 case TIOCGPGRP: 455 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 456 u.u_error = EFAULT; 457 break; 458 459 /* 460 * Modify local mode word. 461 */ 462 case TIOCLBIS: 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 TIOCLBIC: 470 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 471 u.u_error = EFAULT; 472 else 473 tp->t_local &= ~temp; 474 break; 475 476 case TIOCLSET: 477 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 478 u.u_error = EFAULT; 479 else 480 tp->t_local = temp; 481 break; 482 483 case TIOCLGET: 484 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 485 u.u_error = EFAULT; 486 break; 487 488 /* 489 * Return number of characters in 490 * the output. 491 */ 492 case TIOCOUTQ: 493 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 494 u.u_error = EFAULT; 495 break; 496 497 /* 498 * Simulate typing of a character at the terminal. 499 */ 500 case TIOCSTI: 501 c = fubyte(addr); 502 if (u.u_uid && u.u_ttyp != tp || c < 0) 503 u.u_error = EFAULT; 504 else 505 (*linesw[tp->t_line].l_rint)(c, tp); 506 break; 507 /* end of locals */ 508 509 default: 510 return(0); 511 } 512 return(1); 513 } 514