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