1 /* tty.c 3.17 09/20/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 * If the ioctl involves modification, 211 * insist on being able to write the device, 212 * and hang if in the background. 213 */ 214 switch(com) { 215 216 case TIOCHPCL: 217 case TIOCFLUSH: 218 case TIOCSETC: 219 case TIOCSLTC: 220 case TIOCSPGRP: 221 case TIOCLBIS: 222 case TIOCLBIC: 223 case TIOCLSET: 224 case TIOCSTI: 225 if ((flag & FWRITE) == 0) { 226 u.u_error = EBADF; 227 return (1); 228 } 229 while (tp->t_line == NTTYDISC && 230 u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 231 (u.u_procp->p_flag&SVFORK) == 0 && 232 u.u_signal[SIGTTOU] != SIG_IGN && 233 u.u_signal[SIGTTOU] != SIG_HOLD && 234 (u.u_procp->p_flag&SDETACH)==0) { 235 gsignal(u.u_procp->p_pgrp, SIGTTOU); 236 sleep((caddr_t)&lbolt, TTOPRI); 237 } 238 break; 239 } 240 241 /* 242 * Process the ioctl. 243 */ 244 switch(com) { 245 246 /* 247 * Get discipline number 248 */ 249 case TIOCGETD: 250 t = tp->t_line; 251 if (copyout((caddr_t)&t, addr, sizeof(t))) 252 u.u_error = EFAULT; 253 break; 254 255 /* 256 * Set line discipline 257 */ 258 case TIOCSETD: 259 if (copyin(addr, (caddr_t)&t, sizeof(t))) { 260 u.u_error = EFAULT; 261 break; 262 } 263 if (t >= nldisp) { 264 u.u_error = ENXIO; 265 break; 266 } 267 (void) spl5(); 268 if (tp->t_line) 269 (*linesw[tp->t_line].l_close)(tp); 270 if (t) 271 (*linesw[t].l_open)(dev, tp, addr); 272 if (u.u_error==0) 273 tp->t_line = t; 274 (void) spl0(); 275 break; 276 277 /* 278 * Prevent more opens on channel 279 */ 280 case TIOCEXCL: 281 tp->t_state |= XCLUDE; 282 break; 283 284 case TIOCNXCL: 285 tp->t_state &= ~XCLUDE; 286 break; 287 288 /* 289 * Set new parameters 290 */ 291 case TIOCSETP: 292 case TIOCSETN: 293 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 294 u.u_error = EFAULT; 295 return(1); 296 } 297 (void) spl5(); 298 if (tp->t_line == 0) { 299 if (com == TIOCSETP) 300 wflushtty(tp); 301 while (canon(tp)>=0) 302 ; 303 } else if (tp->t_line == NTTYDISC) { 304 if (tp->t_flags&RAW || iocb.sg_flags&RAW || 305 com == TIOCSETP) 306 wflushtty(tp); 307 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 308 if (iocb.sg_flags & CBREAK) { 309 catq(&tp->t_rawq, &tp->t_canq); 310 tq = tp->t_rawq; 311 tp->t_rawq = tp->t_canq; 312 tp->t_canq = tq; 313 } else { 314 tp->t_local |= LPENDIN; 315 if (tp->t_canq.c_cc) 316 panic("ioccom canq"); 317 if (tp->t_chan) 318 (void) sdata(tp->t_chan); 319 else 320 wakeup((caddr_t)&tp->t_rawq); 321 } 322 } 323 } 324 if ((tp->t_state&SPEEDS)==0) { 325 tp->t_ispeed = iocb.sg_ispeed; 326 tp->t_ospeed = iocb.sg_ospeed; 327 } 328 tp->t_erase = iocb.sg_erase; 329 tp->t_kill = iocb.sg_kill; 330 tp->t_flags = iocb.sg_flags; 331 (void) spl0(); 332 break; 333 334 /* 335 * Send current parameters to user 336 */ 337 case TIOCGETP: 338 iocb.sg_ispeed = tp->t_ispeed; 339 iocb.sg_ospeed = tp->t_ospeed; 340 iocb.sg_erase = tp->t_erase; 341 iocb.sg_kill = tp->t_kill; 342 iocb.sg_flags = tp->t_flags; 343 if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 344 u.u_error = EFAULT; 345 break; 346 347 /* 348 * Hang up line on last close 349 */ 350 case TIOCHPCL: 351 tp->t_state |= HUPCLS; 352 break; 353 354 case TIOCFLUSH: 355 flushtty(tp, FREAD|FWRITE); 356 break; 357 358 /* 359 * Ioctl entries to line discipline 360 */ 361 case DIOCSETP: 362 case DIOCGETP: 363 if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 364 u.u_error = ENOTTY; 365 break; 366 367 /* 368 * Set and fetch special characters 369 */ 370 case TIOCSETC: 371 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 372 u.u_error = EFAULT; 373 break; 374 375 case TIOCGETC: 376 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 377 u.u_error = EFAULT; 378 break; 379 380 /* local ioctls */ 381 /* 382 * Set/get local special characters. 383 */ 384 case TIOCSLTC: 385 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 386 u.u_error = EFAULT; 387 break; 388 389 case TIOCGLTC: 390 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 391 u.u_error = EFAULT; 392 break; 393 394 /* 395 * Return number of characters immediately available. 396 */ 397 case FIONREAD: { 398 off_t nread; 399 400 switch (tp->t_line) { 401 402 case NETLDISC: 403 nread = tp->t_rec ? tp->t_inbuf : 0; 404 break; 405 406 case 0: 407 (void) spl5(); 408 while (canon(tp)>=0) 409 ; 410 (void) spl0(); 411 /* fall into ... */ 412 413 case NTTYDISC: 414 nread = tp->t_canq.c_cc; 415 if (tp->t_flags & (RAW|CBREAK)) 416 nread += tp->t_rawq.c_cc; 417 break; 418 419 } 420 if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 421 u.u_error = EFAULT; 422 break; 423 } 424 425 /* 426 * Should allow SPGRP and GPGRP only if tty open for reading. 427 */ 428 case TIOCSPGRP: 429 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 430 u.u_error = EFAULT; 431 break; 432 433 case TIOCGPGRP: 434 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 435 u.u_error = EFAULT; 436 break; 437 438 /* 439 * Modify local mode word. 440 */ 441 case TIOCLBIS: 442 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 443 u.u_error = EFAULT; 444 else 445 tp->t_local |= temp; 446 break; 447 448 case TIOCLBIC: 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 TIOCLSET: 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 TIOCLGET: 463 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 464 u.u_error = EFAULT; 465 break; 466 467 /* 468 * Return number of characters in 469 * the output. 470 */ 471 case TIOCOUTQ: 472 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 473 u.u_error = EFAULT; 474 break; 475 476 /* 477 * Simulate typing of a character at the terminal. 478 */ 479 case TIOCSTI: 480 c = fubyte(addr); 481 if (u.u_uid && u.u_ttyp != tp || c < 0) 482 u.u_error = EFAULT; 483 else 484 (*linesw[tp->t_line].l_rint)(c, tp); 485 break; 486 /* end of locals */ 487 488 default: 489 return(0); 490 } 491 return(1); 492 } 493